C++ Difference Between Std::ref(T) And T&?


Answer :

Well ref constructs an object of the appropriate reference_wrapper type to hold a reference to an object. Which means when you apply:

auto r = ref(x); 

This returns a reference_wrapper and not a direct reference to x (ie T&). This reference_wrapper (ie r) instead holds T&.

A reference_wrapper is very useful when you want to emulate a reference of an object which can be copied (it is both copy-constructible and copy-assignable).

In C++, once you create a reference (say y) to an object (say x), then y and x share the same base address. Furthermore, y cannot refer to any other object. Also you cannot create an array of references ie code like this will throw an error:

#include <iostream> using namespace std;  int main() {     int x=5, y=7, z=8;     int& arr[] {x,y,z};    // error: declaration of 'arr' as array of references     return 0; } 

However this is legal:

#include <iostream> #include <functional>  // for reference_wrapper using namespace std;  int main() {     int x=5, y=7, z=8;     reference_wrapper<int> arr[] {x,y,z};     for (auto a: arr)         cout << a << " ";     return 0; } /* OUTPUT: 5 7 8 */ 

Talking about your problem with cout << is_same<T&,decltype(r)>::value;, the solution is:

cout << is_same<T&,decltype(r.get())>::value;  // will yield true 

Let me show you a program:

#include <iostream> #include <type_traits> #include <functional> using namespace std;  int main() {     cout << boolalpha;     int x=5, y=7;     reference_wrapper<int> r=x;   // or auto r = ref(x);     cout << is_same<int&, decltype(r.get())>::value << "\n";     cout << (&x==&r.get()) << "\n";     r=y;     cout << (&y==&r.get()) << "\n";     r.get()=70;     cout << y;     return 0; } /* Ouput: true true true 70 */ 

See here we get to know three things:

  1. A reference_wrapper object (here r) can be used to create an array of references which was not possible with T&.

  2. r actually acts like a real reference (see how r.get()=70 changed the value of y).

  3. r is not same as T& but r.get() is. This means that r holds T& ie as its name suggests is a wrapper around a reference T&.

I hope this answer is more than enough to explain your doubts.


std::reference_wrapper is recognized by standard facilities to be able to pass objects by reference in pass-by-value contexts.

For example, std::bind can take in the std::ref() to something, transmit it by value, and unpacks it back into a reference later on.

void print(int i) {     std::cout << i << '\n'; }  int main() {     int i = 10;      auto f1 = std::bind(print, i);     auto f2 = std::bind(print, std::ref(i));      i = 20;      f1();     f2(); } 

This snippet outputs :

10 20 

The value of i has been stored (taken by value) into f1 at the point it was initialized, but f2 has kept an std::reference_wrapper by value, and thus behaves like it took in an int&.


A reference (T& or T&&) is a special element in C++ language. It allows to manipulate an object by reference and has special use cases in the language. For example, you cannot create a standard container to hold references: vector<T&> is ill formed and generates a compilation error.

A std::reference_wrapper on the other hand is a C++ object able to hold a reference. As such, you can use it in standard containers.

std::ref is a standard function that returns a std::reference_wrapper on its argument. In the same idea, std::cref returns std::reference_wrapper to a const reference.

One interesting property of a std::reference_wrapper, is that it has an operator T& () const noexcept;. That means that even if it is a true object, it can be automatically converted to the reference that it is holding. So:

  • as it is a copy assignable object, it can be used in containers or in other cases where references are not allowed
  • thanks to its operator T& () const noexcept;, it can be used anywhere you could use a reference, because it will be automatically converted to it.

Comments

Popular posts from this blog

Are Regular VACUUM ANALYZE Still Recommended Under 9.1?

Can Feynman Diagrams Be Used To Represent Any Perturbation Theory?