In order to stem the argument going on in the comments of an answer I gave recently, I'd like some constructive answers to the following questions:
Example code by Ben Voigt and simplified (run it on ideone.com):
#include <iostream>
#include <new>
struct something
{
int i;
};
int main(void)
{
char buffer[sizeof (something) + 40];
something* p = new (buffer) something;
p->i = 11;
int& outlives = p->i;
std::cout << outlives << "\n";
p->~something(); // p->i dies with its parent object
new (p) char[40]; // memory is reused, lifetime of *p (and p->i) is so done
new (&outlives) int(13);
std::cout << outlives << "\n"; // but reference is still alive and well
// and useful, because strict aliasing was respected
}
Is a reference's lifetime distinct from the object it refers to? Is a reference simply an alias for its target?
A reference has its own lifetime:
int x = 0;
{
int& r = x;
} // r dies now
x = 5; // x is still alive
A ref-to-const
additionally may extend the lifetime of its referee:
int foo() { return 0; }
const int& r = foo(); // note, this is *not* a reference to a local variable
cout << r; // valid; the lifetime of the result of foo() is extended
though this is not without caveats:
A reference to const only extends the lifetime of a temporary object if the reference is a) local and b) bound to a prvalue whose evaluation creates said temporary object. (So it doesn't work for members, or local references which are bound to xvalues.) Also, non-const rvalue references extend the lifetime in the exact same fashion. [@FredOverflow]
Can a reference outlive its target in a well-formed program without resulting in undefined behaviour?
Sure, as long as you don't use it.
Can a reference be made to refer to a new object if the storage allocated for the original object is reused?
Yes, under some conditions:
[C++11: 3.8/7]:
If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:
- the storage for the new object exactly overlays the storage location which the original object occupied, and
- the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
- the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and
- the original object was a most derived object (1.8) of type T and the new object is a most derived object of type T (that is, they are not base class subobjects).
Does the following code demonstrate the above points without invoking undefined behaviour?
Tl;dr.
Yes. For example local nonstatic references have automatic storage duration and corresponding liifetime and can refer to objects that have longer lifetime.
Yes, dangling references are an example. As long as such references are not used in any expressions when they become dangling, they are fine.
There is a special rule in clause 3 about this case. Names of objects, pointers and references automatically refer to the new object that reuses the storage under restricted conditions. I believe it is at the end of 3.8. Someone who has the spec handy please fill in the correct ref here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With