根据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(obj)初始化 Parent 时, obj 的值尚未初始化。
这在gcc下编译得很好,我确实得到了正确的输出,但是我不确定标准或良好的编码实践是否反对它。这是一个未定义的行为吗?如果没有,我应该避免这种不良做法吗?
答案 0 :(得分:2)
首先,让我澄清一件事。 我不确定是否甚至可以复制引用。
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。 这样,我得出一个结论,即未初始化(但已经分配)的对象是明确定义的。
如果您发现任何错误,请在评论中告诉我。也可以随意编辑这个答案。
修改强> 我只是想说,这样的结论似乎是合理的。对象的初始化不能改变其在内存中的位置。即使在初始化之前存储对已分配内存的引用有什么不好?