在c ++

时间:2017-08-27 07:54:50

标签: c++ reference initializer-list

根据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下编译得很好,我确实得到了正确的输出,但是我不确定标准或良好的编码实践是否反对它。这是一个未定义的行为吗?如果没有,我应该避免这种不良做法吗?

1 个答案:

答案 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。 这样,我得出一个结论,即未初始化(但已经分配)的对象是明确定义的。

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

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