Marius Herzog Marius Herzog - 5 days ago 6
C++ Question

C++ chaining references with locals in between

I have multiple references referencing other references, but some of these references in between are contained in an object which goes out of scope (or is destructed) before the final object referenced to.

That is, the object being referenced has a longer lifetime than the references in between. Now, is accessing the first reference undefined behaviour?

It is hard to explain, but the following code should be clearer:

#include <iostream>


static const int x = 10;

struct Q
{
const int& q = x;
};

void foo(int& v)
{
Q q;
v = q.q;
} // q goes out of scope


int main()
{
int n = 4;
foo(n);
std::cout << n;
}


It seems to work fine for me and clang and gcc do not give me warnings either.

Answer

You do not have undefined behaviour, because unlike what your description apparently wants to say, there are no dangling references in your code.

Let's review the code considering the individual lifetimes of all objects:

static const int x = 10;

This int object will live longer than all local objects. It will outlive everything else in your example program.

struct Q
{
   const int& q = x;
};

An instance of Q will not have any problems as long as the instance itself does not outlive the x object. If you only have local Q instances, then you're fine. [1]

void foo(int& v)
{

Here we have a modifiable int object from outside the function. Its name within foo is v.

   Q q;
   v = q.q;

The int object outside the function is assigned the value of the x object via the reference in q.

} // q goes out of scope

Yes, and this does not matter. The int object outside the function has already received its new value. It does no longer depend in any way on the lives of q or even x.

int main()
{
   int n = 4;

Here begins the life of an int object, named n from within main...

   foo(n);

... and v from within foo.

After the call, foo has done its job, and n has received a new value.

   std::cout << n;
}

The value of n is read. Then, n is destroyed. Finally, x is destroyed. No problems, no undefined behaviour.


[1] Things would indeed get a bit more complicated if you had a static Q instance in a different translation unit.

Comments