在 C++ 中复制对未初始化对象的引用
Copying a reference to an uninitialized object in c++
根据c++标准,在初始化它引用的对象之前复制一个引用是未定义的行为吗?这发生在下面的例子中,我传递了一个对父对象 class 的引用,然后我才初始化对象的值,因为对父构造函数的调用必须在初始化列表中排在第一位。
#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;
}
这里用Parent(obj)初始化Parent时,obj的值还没有初始化。
这在 gcc 下编译得很好,我确实得到了正确的输出,但我不确定标准或良好的编码实践是否反对它。这是未定义的行为吗?如果不是,我应该避免这种不良做法吗?
首先,让我澄清一件事。
我不确定是否可以从字面上 复制引用 。
int i = 10;
int& ref = i; // since this moment ref becomes "untouchable"
int& alt_ref = ref; // actually, means int& alt_ref = i;
我认为如果 ref
是某个 class 的成员并且您复制了这个 class 的一个实例,也会发生同样的情况。
此外,如果你仔细观察你的代码,你甚至没有 "copy a reference",而是用未初始化的(尚未)对象初始化一个引用。
struct Parent
{
Object& ref;
Parent(Object& i): ref(i) { }
};
struct Child : Parent
{
Object obj;
Child(int i): Parent(obj), obj(i) { }
};
物理上等同于:
struct Child
{
Object& ref;
Object obj;
Child(int i): ref(obj), obj(i) { }
};
话虽这么说,你的问题实际上意味着:
Is it undefined behavior to initialize a reference before
initializing the object it is about to refer?
这里引用 C++ 标准 (§3.8.6 [basic.life/6]) 可能给出了答案:
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.
而 §12.7.1 [class.cdtor/1] 只是说:
...referring to any non-static member or base class of the object
before the constructor begins execution results in undefined behavior.
§12.7.1 仅提及 "referring to objects members",因此 "referring to the object itself" 属于 §3.8.6。
这样,我得出的结论是,引用未初始化(但已分配)的对象是明确定义的。
如果您发现任何错误,请在评论中告诉我。也可以随时编辑此答案。
编辑:
我只想说,这样的结论似乎是有道理的。对象的初始化不能改变它在内存中的位置。在初始化之前存储对已分配内存的引用有什么不好?
根据c++标准,在初始化它引用的对象之前复制一个引用是未定义的行为吗?这发生在下面的例子中,我传递了一个对父对象 class 的引用,然后我才初始化对象的值,因为对父构造函数的调用必须在初始化列表中排在第一位。
#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;
}
这里用Parent(obj)初始化Parent时,obj的值还没有初始化。
这在 gcc 下编译得很好,我确实得到了正确的输出,但我不确定标准或良好的编码实践是否反对它。这是未定义的行为吗?如果不是,我应该避免这种不良做法吗?
首先,让我澄清一件事。 我不确定是否可以从字面上 复制引用 。
int i = 10;
int& ref = i; // since this moment ref becomes "untouchable"
int& alt_ref = ref; // actually, means int& alt_ref = i;
我认为如果 ref
是某个 class 的成员并且您复制了这个 class 的一个实例,也会发生同样的情况。
此外,如果你仔细观察你的代码,你甚至没有 "copy a reference",而是用未初始化的(尚未)对象初始化一个引用。
struct Parent
{
Object& ref;
Parent(Object& i): ref(i) { }
};
struct Child : Parent
{
Object obj;
Child(int i): Parent(obj), obj(i) { }
};
物理上等同于:
struct Child
{
Object& ref;
Object obj;
Child(int i): ref(obj), obj(i) { }
};
话虽这么说,你的问题实际上意味着:
Is it undefined behavior to initialize a reference before initializing the object it is about to refer?
这里引用 C++ 标准 (§3.8.6 [basic.life/6]) 可能给出了答案:
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.
而 §12.7.1 [class.cdtor/1] 只是说:
...referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior.
§12.7.1 仅提及 "referring to objects members",因此 "referring to the object itself" 属于 §3.8.6。 这样,我得出的结论是,引用未初始化(但已分配)的对象是明确定义的。
如果您发现任何错误,请在评论中告诉我。也可以随时编辑此答案。
编辑: 我只想说,这样的结论似乎是有道理的。对象的初始化不能改变它在内存中的位置。在初始化之前存储对已分配内存的引用有什么不好?