将引用复制到C++中的未初始化对象

问题描述:

根据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; 
} 

这里时家长与父(OBJ)初始化的OBJ的价值还没有被初始化。

这编译好gcc下,我得到一个正确的输出,但我不知道是否标准或良好的编码实践建议反对它。这是一个未定义的行为?如果不是,我应该避免这是一种糟糕的做法吗?

+2

您没有未初始化的引用,而是对未初始化的对象的引用。这与您从标准中引用的情况不同,只要“Parent”在所有内容初始化之前都不使用引用,代码就可以。 –

+0

谢谢,我更新了标题以反映您的评论。你说的话确实有意义,因为它是指向未初始化对象的指针会发生什么。 – Flynsee

+0

Bos的评论也回答了你的问题吗?还是你编辑来澄清你问的不同之处? – Yunnosch

首先,让我澄清一件事。 我不确定是否可以从字面上复制参考

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]),其可能给出的答案:

类似地,对象的生存期开始之前,但后该对象将占用的存储器已经被分配,或者在对象的生命周期结束之后并且在重新使用或释放​​对象所占据的存储器之前,可以使用任何引用原始对象的glvalue,但仅可以使用该对象以有限的方式。对于正在建设或销毁的物体 ,请参阅12.7。否则,这样一个glvalue 引用分配的存储(3.7.4.2),并且使用不依赖于它的值的glvalue的属性是明确定义的。

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

...构造之前提及任何非静态成员或基类对象 的开始执行结果在未定义的行为。

仅§12.7.1提到“在涉及对象成员”,因此“指的是对象本身”落在下§3.8.6。 这样,我得出的结论是,引用未初始化(但已分配)的对象是明确的。

如果您发现任何错误,请在评论中告知我。也可以随意编辑这个答案。

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

+1

第二段是问题的关键,实际上是答案的来源。所说的答案是“你做什么是好的,但如果你使用提到的对象,它会中断”。此外,它将适用于按部分标题而不是数字来引用段落。部分数字往往会有所变化,部分名称不是很多。因此,例如[basic.life/6]而不是§3.8.6(在即将到来的C++ 17中是6.8.7)。 – StoryTeller

+0

非常感谢。正如你所说的:“可以使用但仅限于有限的方式”似乎表明,在§12.7.1之外,使用该对象是很好的。就内存管理而言,这是合理的和预期的。 – Flynsee