Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is the use of std::ref necessary?

Consider:

std::tuple<int , const A&> func (const A& a) 
{
  return std::make_tuple( 0 , std::ref(a) );
}

Is the std::ref required for writing correct and portable code? (It compiles fine without it)

Background:

If I remove std::ref my code builds fine without any warnings (g++-4.6 -Wall), but doesn't run correctly.

In case of interest the definition of A:

struct A {
  std::array<int,2> vec;
  typedef int type_t;

  template<typename... OPs,typename... VALs>
  A& operator=(const std::pair< std::tuple<VALs...> , std::tuple<OPs...> >& e) {
    for( int i = 0 ; i < vec.size() ; ++i ) {
      vec[i] = eval( extract(i,e.first) , e.second );
    }
  }
};
like image 505
ritter Avatar asked Aug 06 '12 17:08

ritter


People also ask

What is the purpose of std :: ref?

std::ref. Constructs an object of the appropriate reference_wrapper type to hold a reference to elem . If the argument is itself a reference_wrapper (2), it creates a copy of x instead. The function calls the proper reference_wrapper constructor.

What does REF do in C++?

C++ References. C++ references allow you to create a second name for the a variable that you can use to read or modify the original data stored in that variable.

What is the use of reference_wrapper?

A reference_wrapper<Ty> is a copy constructible and copy assignable wrapper around a reference to an object or a function of type Ty , and holds a pointer that points to an object of that type. A reference_wrapper can be used to store references in standard containers, and to pass objects by reference to std::bind .


4 Answers

One of the example where std::ref is necessary:

void update(int &data)  //expects a reference to int
{
    data = 15;
}
int main()
{
    int data = 10;

    // This doesn't compile as the data value is copied when its reference is expected.
    //std::thread t1(update, data);         

    std::thread t1(update, std::ref(data));  // works

    t1.join();
    return 0;
}

The std::thread constructor copies the supplied values, without converting to the expected argument type (which is reference type in this case, seeupdate()). So we need to wrap the arguments that really needs to be references in std::ref.

like image 117
Saurav Sahu Avatar answered Oct 06 '22 23:10

Saurav Sahu


std::ref does not make a reference, so in your code sample it doesn't do what you expect. std::ref creates an object that behaves similarly to a reference. It may be useful, for example, when you want to instantiate a functor, and pass a reference-like version of it to a standard library algorithm. Since algorithms take functors by value, you can use std::ref to wrap the functor.

like image 43
juanchopanza Avatar answered Oct 07 '22 00:10

juanchopanza


  • make_tuple(0, a) makes a tuple<int, A>.
  • make_tuple(0, ref(a)) makes a tuple<int, reference_wrapper<A>>.
  • You can also say tuple<int, A&> t(0, a); for a tuple you can't make with make_tuple, or use std::tie.
like image 27
Kerrek SB Avatar answered Oct 07 '22 01:10

Kerrek SB


Answering the question in the title (When is the use of std::ref necessary?): Another case where std::ref is useful is when looping over a list of references to objects and modify them:

std::vector<int> v1, v2;
  
void test() {
  for (std::vector<int>& vv : 
    // Compiles
    { std::ref(v1), std::ref(v2) } 
  
    // Compiler rejects this with:
    //   binding reference of type 'vector<...>' to value of 
    //   type 'const vector<...>' drops 'const' qualifier 
    // { v1, v2} 
  ) {
      vv.push_back(3);
  }
}

Without using std::ref in the list, the objects are treated as const and can't be modified (see also https://godbolt.org/z/Ta6YM31KM).

like image 26
Andre Holzner Avatar answered Oct 07 '22 00:10

Andre Holzner