According to the c++ standard, is it undefined behavior to copy a reference before initializing the object it refers to? This happens in the following example, where I pass a reference to a parent class and I initialize the value of the object only after because the call to the parent constructor has to be first in the initializer list.
#include <iostream>
struct Object
{
int val;
Object(int i): val(i) {}
};
struct Parent
{
Object& ref;
Parent(Object& i): ref(i){}
};
struct Child : Parent
{
Object obj;
Child(int i): Parent(obj), obj(i) {}
};
int main()
{
std::cout << Child(3).ref.val;
}
Here when Parent is initialized with Parent(obj), the value of obj has not been initialized yet.
This compiles fine under gcc, and I do get a correct output, but I'm not sure whether the standard or good coding practice advise against it. Is it an undefined behavior ? And if not, is it a bad practice that I should avoid?
Firstly, let me clarify one thing. I am not sure if it is even possible to literally copy a reference.
int i = 10;
int& ref = i; // since this moment ref becomes "untouchable"
int& alt_ref = ref; // actually, means int& alt_ref = i;
I think the same happens if ref
is a member of some class and you copy an instance of this class.
Besides, if you look closer on your code, you don't even "copy a reference", but rather initialize a reference with uninitialized (yet) object.
struct Parent
{
Object& ref;
Parent(Object& i): ref(i) { }
};
struct Child : Parent
{
Object obj;
Child(int i): Parent(obj), obj(i) { }
};
physically is equivalent to:
struct Child
{
Object& ref;
Object obj;
Child(int i): ref(obj), obj(i) { }
};
With that being said, your question actually means:
Is it undefined behavior to initialize a reference before initializing the object it is about to refer?
Here is a quote from C++ Standard (§3.8.6 [basic.life/6]) which possibly gives the answer:
Similarly, before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any glvalue that refers to the original object may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a glvalue refers to allocated storage (3.7.4.2), and using the properties of the glvalue that do not depend on its value is well-defined.
And §12.7.1 [class.cdtor/1] just says:
...referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior.
§12.7.1 mentions only "referring to objects members", hence "referring to the object itself" falls under §3.8.6. This way, I make a conclusion that referring to uninitialized (but already allocated) object is well-defined.
If you see any mistakes, please let me know in the comments. Also feel free to edit this answer.
Edit: I just want to say, that such conclusion seems reasonable. Initialization of an object cannot change its location in memory. What is bad in storing the reference to already allocated memory even before it is initialized?