在 c++ 中复制对未初始化对象的引用



根据 c++ 标准,在初始化引用的对象之前复制引用是否是未定义的行为?这发生在下面的示例中,我传递对父类的引用,并且仅在初始化对象之后初始化对象的值,因为对父构造函数的调用必须在初始值设定项列表中排在第一位。

#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 使用Parent(obj) 初始化时,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是某个类的成员并且您复制了该类的实例,也会发生同样的情况。 此外,如果你仔细观察你的代码,你甚至不会"复制引用",而是使用未初始化的(尚未)对象初始化引用。

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) { }
};

话虽如此,您的问题实际上意味着:

在初始化引用之前是否是未定义的行为 初始化它即将引用的对象?

以下是C++标准(§3.8.6 [basic.life/6])的引文,可能给出了答案:

同样,在对象的生存期开始之前,但在 对象将占用的存储已分配,或者在 对象的生存期已经结束,并且在存储之前 占用的对象被重复使用或释放,任何引用 可以使用原始对象,但只能以有限的方式使用。对于对象 正在建造或销毁中,见12.7。否则,这样的glvalue 指分配的存储 (3.7.4.2),并使用 不依赖于其值的glvalue是明确定义的。

§12.7.1 [class.cdtor/1] 只是说:

。引用对象的任何非静态成员或基类 在构造函数开始执行之前会导致未定义的行为。

§12.7.1只提到"指对象成员",因此"指对象本身"属于§3.8.6。 这样,我得出的结论是,引用未初始化(但已分配)的对象是明确定义的。

如果您看到任何错误,请在评论中告诉我。也可以随意编辑此答案。

编辑:我只想说,这样的结论似乎是合理的。对象的初始化不能更改其在内存中的位置。甚至在初始化之前存储对已分配内存的引用有什么不好?

最新更新