I thought of a strange cheat in C++. Normally, I can’t smuggle a reference out of a scope because I can’t define an uninitialized reference in the containing scope. However, I can define a pointer to a class containing a reference, fail to initialize it, and then assign it the address of some dynamic memory initialized to a local variable. Even though that dynamic object contains a reference to a variable that is supposed to go out of scope, the pointed-to object still has a valid reference with the same value! g++ doesn’t complain even if I tell it to be -pedantic, so I assume it’s valid. But how, and why?
struct int_ref
{
int &x;
int_ref(int &i): x(i) {}
};
#include <iostream>
using namespace std;
int main(void)
{
int_ref *irp;
int i = 1;
int_ref a(i); // Creates an int_ref initialized to i
irp = &a; // irp is now a pointer to a reference!
// Prints 1
cout << "irp->x = " << irp->x << " (i = " << i << ")" << endl;
i = 2;
// Prints 2
cout << "irp->x = " << irp->x << " (i = " << i << ")" << endl;
int j = 3;
int_ref b(j);
irp = &b;
// Prints 3
cout << "irp->x = " << irp->x << " (i = " << i << ", j = " << j << ")" << endl;
i = 1;
// Still prints 3
cout << "irp->x = " << irp->x << " (i = " << i << ", j = " << j << ")" << endl;
{
int k = 4;
irp = new int_ref(k);
// k goes out of scope
}
int k = 1; // Doesn't affect the other k, of course
// Prints 4 ?!
cout << "irp->x = " << irp->x << " (i = " << i << ", j = " << j << ")" << endl;
}
Edit: This may in fact be (as suggested in the answers) an undiagnosed dangling reference. What about if I define int_ref like this:
struct int_ref
{
const int &x;
int_ref(const int &i): x(i) {}
};
A const reference need not refer to an lvalue, so there is no well-defined concept of a dangling one. Is the code still undefined?
Just because your compiler doesn’t emit a diagnostic for your program doesn’t mean that your program is good, valid and safe.
Your final line invokes Undefined Behaviour because you have a dangling reference. This does not need to be diagnosed by the compiler, but it also doesn’t make it right. You could get
4(just so happens to still be at that place in memory), you could get some other value, you could get a segmentation fault, or your PC could explode.Just don’t do this.
Terminology note: there’s no “pointer to reference” (no such thing exists) here, only a pointer to an
int_ref.