#include <functional>
int main() {
int a = 2;
int b = 4;
auto ref = std::ref(a);
//std::reference_wrapper<int> ref = std::ref(a); <- Or with the type specified
ref = std::ref(b);
}
This is also useful for storing references in containers.
You can make a reference wrapper very easy using the placement new:
template< class T >
class RefWrapper
{
public:
RefWrapper( T& v ) : m_v( v ){}
operator T&(){ return m_v; }
T& operator=( const T& a ){ m_v = a; return m_v;}
//...... //
void remap( T& v )
{
//re-map reference
new (this) RefWrapper(v);
}
private:
T& m_v;
};
int32 a = 0;
int32 b = 0;
RefWrapper< int > r( a );
r = 1; // a = 1 now
r.remap( b );
r = 2; // b = 2 now
Formally speaking, that is impossible as it is forbidden by design. Arbitrarily speaking, that is possible.
A references is stored as a pointer, so you can always change where it points to as long as you know how to get its address. Similarly, you can also change the value of const variables, const member variables or even private member variables when you don't have access to.
For example, the following code has changed class A's const private member reference:
#include <iostream>
using namespace std;
class A{
private:
const int &i1;
public:
A(int &a):i1(a){}
int geti(){return i1;}
int *getip(){return (int*)&i1;}
};
int main(int argc, char *argv[]){
int i=5, j=10;
A a(i);
cout << "before change:" << endl;
cout << "&a.i1=" << a.getip() << " &i=" << &i << " &j="<< &j << endl;
cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl;
i=6; cout << "setting i to 6" << endl;
cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl;
*(int**)&a = &j; // the key step that changes A's member reference
cout << endl << "after change:" << endl;
cout << "&a.i1=" << a.getip() << " &i=" << &i << " &j="<< &j << endl;
cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl;
j=11; cout << "setting j to 11" << endl;
cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl;
return 0;
}
Program output:
before change:
&a.i1=0x7fff1b624140 &i=0x7fff1b624140 &j=0x7fff1b624150
i=5 j=10 a.i1=5
setting i to 6
i=6 j=10 a.i1=6
after change:
&a.i1=0x7fff1b624150 &i=0x7fff1b624140 &j=0x7fff1b624150
i=6 j=10 a.i1=10
setting j to 11
i=6 j=11 a.i1=11
As you can see that a.i1 initially points to i, after the change, it points to j.
However, doing so is considered as dangerous and thus unrecommended, because it defeats the original purpose of data encapsulation and OOP. It is more like memory address hacking.
However, if you store your reference in a class or struct, you could re-create the whole thing using placement new, so the reference is re-bound. As @HolyBlackCat noted, don't forget to use std::launder to access the re-created object or use the pointer returned from the placement new. Consider my example:
#include <iostream>
struct A {
A(int& ref) : ref(ref) {}
// A reference stored as a field
int& ref;
};
int main() {
int a = 42;
int b = 43;
// When instance is created, the reference is bound to a
A ref_container(a);
std::cout <<
"&ref_container.ref = " << &ref_container.ref << std::endl <<
"&a = " << &a << std::endl << std::endl;
// Re-create the instance, and bind the reference to b
A* new_ref_container = new(&ref_container) A(b);
std::cout <<
// &ref_container and new_ref_container are the same pointers
"&ref_container = " << &ref_container << std::endl <<
"new_ref_container = " << new_ref_container << std::endl <<
"&new_ref_container.ref = " << &new_ref_container->ref << std::endl <<
"&b = " << &b << std::endl << std::endl;
return 0;
}