106

If I have this:

int a = 2;
int b = 4;
int &ref = a;

How can I make ref refer to b after this code?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
Taru
  • 2,562
  • 4
  • 22
  • 30

10 Answers10

124

This is not possible, and that's by design. References cannot be rebound.

Community
  • 1
  • 1
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • 2
    In the code below, I am changing reference of x to k and still getting result. Can you tell me how this is possible? int a=50; int &x=a; int k=10; cout< – Rajesh Aug 14 '17 at 09:20
  • 15
    You are not changing the reference, you are assigning the value of `k` to the object referred to by `x`. After this assignment, `a == k`, and `x` still refers to `a`. – Björn Pollex Aug 14 '17 at 09:22
106

With C++11 there is the new(ish) std::reference_wrapper.

#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.

Community
  • 1
  • 1
David C. Bishop
  • 6,437
  • 3
  • 28
  • 22
25

You can't reassign a reference, but if you're looking for something that would provide similar abilities to this you can do a pointer instead.

int a = 2;
int b = 4;
int* ptr = &a;  //ptr points to memory location of a.
ptr = &b;       //ptr points to memory location of b now.

You can get or set the value within pointer with: 

*ptr = 5;     //set
int c = *ptr; //get
RainingChain
  • 7,397
  • 10
  • 36
  • 68
John Humphreys
  • 37,047
  • 37
  • 155
  • 255
10

Formally speaking, that is impossible as it is forbidden by design. Practically speaking, that is possible if you want to hack it.

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 reference. The design purpose of reference in C/C++ language is to forbid alterations of its content at programming level. So if it ends up that you need to alter its value, then you should consider define that variable as a pointer instead. Moreover, the solution proposed here is assuming that the reference is implemented as a pointer (which is true in most of the compiler implementations but not all). So it will NOT work when the underlying implementation is not a pointer (and it will cause your program to crash in that case).

xuancong84
  • 1,412
  • 16
  • 17
  • 5
    That is not correct: A reference does not need to be a pointer/object at all. According to the standard it just has to behave like a different label for the same object. Trying to change that is undefined behaviour.If your compiler in your specific program decides to implement it via pointers you can maybe change it, but that could also break at any time. – ABaumstumpf May 08 '20 at 08:26
  • 2
    That is why I mention in the 1st sentence: "formally speaking, that is impossible as it is forbidden by design." I just provided a implementation-level workaround. – xuancong84 Jun 05 '20 at 04:36
  • If the reference is a function argument or member of a class, I think it has to be just a pointer. PS. Why is Cpp trying to be an abstraction language? Is it necessary? – user13947194 Nov 20 '22 at 06:16
  • @user13947194 The language doesn't define it because it doesn't have to, not because it is trying to be overly abstract. In practice every compiler implements it as a pointer. Many will try to adhere to "imaginary" compilers but in my view this is a YAGNI violation and originates from not defining project boundaries. That said, don't change references :) – c z Jun 28 '23 at 12:43
10

You cannot reassign a reference.

Griwes
  • 8,805
  • 2
  • 43
  • 70
6

That's not possible in the way you want. C++ just doesn't let you rebind what a reference points to.

However if you want to use trickery you can almost simulate it with a new scope (NEVER do this in a real program):

int a = 2;
int b = 4;
int &ref = a;

{
    int& ref = b; // Shadows the original ref so everything inside this { } refers to `ref` as `b` now.
}
Mark B
  • 95,107
  • 10
  • 109
  • 188
3

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
Werner Henze
  • 16,404
  • 12
  • 44
  • 69
Taster
  • 49
  • 1
  • 3
    This answer is much more complicated than necessary - the question was very simple and could be answered with one-liner. – lukelazarovic Mar 28 '14 at 10:53
  • If I remember correctly, this is ill-formed pre-C++20 because of the lack of `std::launder`. You could've just used a pointer. – HolyBlackCat Nov 12 '20 at 12:16
3

This is possible. Because under the hood, reference is a pointer. The following code will print "hello world"

#include "stdlib.h"
#include "stdio.h"
#include <string>

using namespace std;

class ReferenceChange
{
public:
    size_t otherVariable;
    string& ref;

    ReferenceChange() : ref(*((string*)NULL)) {}

    void setRef(string& str) {
        *(&this->otherVariable + 1) = (size_t)&str;
    }
};

void main()
{
    string a("hello");
    string b("world");

    ReferenceChange rc;

    rc.setRef(a);
    printf("%s ", rc.ref.c_str());

    rc.setRef(b);
    printf("%s\n", rc.ref.c_str());
}
Zhaolin Feng
  • 428
  • 4
  • 8
0

It is impossible, as other answers state.

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;
}

demo

The output is:

&ref_container.ref = 0x7ffdcb5f8c44
&a = 0x7ffdcb5f8c44

&ref_container = 0x7ffdcb5f8c38
new_ref_container = 0x7ffdcb5f8c38
&new_ref_container.ref = 0x7ffdcb5f8c40
&b = 0x7ffdcb5f8c40
ivaigult
  • 6,198
  • 5
  • 38
  • 66
  • 2
    If I remember correctly, this causes UB pre-C++20 because you forgot `std::launder`. – HolyBlackCat Nov 12 '20 at 12:18
  • @HolyBlackCat yeah, I think you're right. The relevant section is [basic.life](https://timsong-cpp.github.io/cppwp/n4659/basic.life#8). I cannot access the new object vie the old pointer/variable. – ivaigult Nov 12 '20 at 12:35
-6

Although its a bad idea as it defeats the purpose of using references, it is possible to change the reference directly

const_cast< int& >(ref)=b;
Mureinik
  • 297,002
  • 52
  • 306
  • 350
visu
  • 45
  • 1
  • 1