2

How does one pass and operate on constant (or non constant) references inside STL containers. Say I have a function:

bool foo(const Obj& A, const Obj& B) {
  // do some computation on A & B
}

and since A & B always occur together, I would like to put them in an STL pair:

bool foo(const  std::pair<Obj, Obj>& A_and_B) {
  // do some computation on A & B
}

However now both objects A & B get copied into a pair every time foo needs to be called. Looking around I found reference_wrapper in C++11. Though doing something like this doesn't quite work:

bool foo(const  std::pair<std::reference_wrapper<Obj>, std::reference_wrapper<Obj>>& A_and_B) {
  // do some computation on A & B
}

bool foo(const  std::pair<Obj, Obj>& A_and_B) {
  foo(std::make_pair(std::ref(A_and_B.first), std::ref(A_and_B.second)));
}

What is the correct way of passing containers with reference values without using pointers?

1
  • There is no "the" correct way, but one option for you is to make the formal argument type pair<Obj const&, Obj const&> const&, or just pair<Obj const&, Obj const&> const. Commented May 24, 2016 at 8:32

4 Answers 4

1

To avoid copy when make_pair, why not define the pair as std::pair<Obj&, Obj&> directly?

#include <iostream>
#include <string>
#include <functional>
class Obj 
{
};

bool foo(const  std::pair<Obj, Obj>& A_and_B) {
  // do some computation on A & B
    std::cout << __func__ << std::endl;
}

bool foo(const  std::pair<Obj&, Obj&>& A_and_B) {
  // do some computation on A & B
    std::cout << "ref version foo" << std::endl;
}

int main( void )
{
    Obj A;
    Obj B;
    foo( std::make_pair(std::ref(A), std::ref(B)) );
    return 0;
}
Sign up to request clarification or add additional context in comments.

1 Comment

You'd want to remove the first overload and change the references to reference to const in the second.
1

Here's one way, passing just a pair of references (no copying):

#include <utility>          // pair
#include <functional>       // ref
#include <iostream>
using namespace std;

struct Obj {};

auto foo( pair<Obj const&, Obj const&> const ab )
{
    Obj const& a = ab.first;
    Obj const& b = ab.second;
    cout << &a << " " << &b << endl;
}

auto main() -> int
{
    Obj a;
    Obj b;
    cout << &a << " " << &b << endl;
    foo( make_pair( ref( a ), ref( b ) ) );
}

This works nicely because std::make_pair has special support for std::reference_wrapper arguments, then deducing reference to the referred to type.

std::reference_wrapper is the result type of std::ref.

1 Comment

I like this, I think it's the cleanest suggestion.
0

Since std::make_pair supports move semantics, you just need to write your function as you suggested, but when calling it move objects A and B into the std::make_pair as shown below:

// Just as you already suggested
bool foo(const  std::pair<Obj, Obj>& A_and_B) {
  // do some computation on A & B
}

Call it as:

int main( void )
{
    Obj A; // work on A
    Obj B; // work on B
    auto A_and_B = std::make_pair(std::move(A), std::move(B)); // effectively moves A and B; no copies!
    // A and B are now reset, but you can use A_and_B.first and A_and_B.second!
    foo( A_and_B  ); 
    return 0;
}

Live demo.

3 Comments

It seems very unlikely the OP wants to move the argument objects.
@Cheersandhth.-Alf It seems everyone is confused and using reference_wrapper is a good evidence of it. I believe the OP wants to tie A and B together without making unnecessary copies.
I agree with that comment, modulo s/everyone/everyone else/g. But moving isn't the answer, because moving (1) for movable types changes the actual arguments, which is undesirable, and (2) for non-movable types reduces to copying, which also is generally undesirable. Passing a pair of references does the job nicely. ;-)
-1

Since you are passing the pair by reference, it is not copied. However, Obj A=A_and_B.first will create a copy. If you want to avoid that, you can get a reference to the element, i.e.

Obj &A=A_and_B.first.

1 Comment

I don't mind the downvote, but I'm curious as to what I got wrong in my answer..?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.