包含对自身的引用的类

时间:2014-02-28 15:10:48

标签: c++ language-lawyer

浏览标准草案(n3242)我在第9.2条(强调我的)中找到了这句话:

  

非静态(9.4)数据成员不得有不完整的类型。在   特别是,C类不应包含类的非静态成员   C,但可以包含指针或引用到类的对象   下进行。

从此我认为可以定义这样的类:

class A {
public:
  A(A& a) : a_(a){
  }
private:
  A& a_;
};

然后在第8.3.2节中,我发现了以下内容:

  

应初始化引用以引用有效对象或   功能

问题1:是否允许定义此类型的对象,并将其名称作为参考:

A a(a);

或者这会触发未定义的行为吗?

问题2:如果是,标准的哪些部分允许从仍待构建的对象初始化引用?

问题3:如果不是,这是否意味着A类的定义形式良好但是没有触发UB就可以创建第一个对象?在这种情况下,这背后的理由是什么?

3 个答案:

答案 0 :(得分:8)

“有效对象”未在标准中的任何位置定义,但它旨在表示具有适当大小和对齐的内存区域,该区域可包含指定类型的对象。它只是意味着排除对诸如解除引用的空指针,未对齐的内存区域等内容的引用。未初始化的对象是有效的。

有一个未解决的问题需要澄清措辞CWG 453

答案 1 :(得分:5)

n3337 § 3.8 / 6

  

同样,在对象的生命周期开始之前但在之后   对象占用的存储空间已被分配,或之后   对象的生命周期已经结束,在存储之前就已经存在了   对象占用被重用或释放,任何引用的glvalue   可以使用原始对象,但仅限于有限的方式。对于一个对象   正在建设或破坏,见12.7。否则,这样的glvalue   指分配存储(3.7.4.2),并使用的属性   不依赖于其值的glvalue是明确定义的。该程序   在以下情况下具有未定义的行为:

     

- 左值到左值的转换(4.1)是   应用于这样的glvalue,

     

- glvalue用于访问a   非静态数据成员或调用非静态成员函数   对象,或

     

- glvalue被隐式转换(4.10)为引用   到基类类型,或

     

- glvalue用作a的操作数   static_cast(5.2.9),除非转换最终是cv   焦炭和放大器;或cv unsigned char&,或

     

- glvalue用作的操作数   dynamic_cast(5.2.7)或作为typeid的操作数。

所以,回答你的问题:

  

问题1:是否允许定义此类型传递的对象   它的名字作为参考?

是。仅使用地址似乎不会违反这一点(至少对于放在堆栈上的变量)。

A a(a);

  

或者会触发未定义的行为吗?

没有

  

问题2:如果是,标准的哪些部分允许   从仍待构造的对象初始化引用?

§ 3.8 / 6(上图)


剩下的唯一问题是这与

的对应关系
  

应初始化引用以引用有效对象或   功能

问题在于术语有效对象。因为§ 8.3.2 / 4表示

  

未指明引用是否需要存储

似乎§ 8.3.2是有问题的,应该重新编写。该错误导致文档 C ++标准核心语言活动问题,修订版87 日期为2014年1月20日的change proposed

  

应初始化引用以引用对象或函数。

     

将8.3.2 [dcl.ref]第4段改为:

     

如果直接绑定引用的左值也不指定   现有的适当类型的对象或功能(8.5.3   [dcl.init.ref]),也不是合适大小和对齐的内存区域   包含引用类型的对象(1.8 [intro.object],3.8   [basic.life],3.9 [basic.types]),行为未定义。

答案 2 :(得分:0)

从n1905,3.3.1.1

  

名称的声明点在完成后立即生效   声明者(第8条)和初始化者(如果有的话)之前,除了   如下所述。

     

[例如:
  int x = 12;
  {int x = x; }

     

这里是第二个x   用自己的(不确定的)值初始化。

     

-end example]

我的重点(如果我错了,请纠正我):在你的例子中 -

A a(a);

相当于 -

A a = a;  // Copy initialization

因此,根据标准a初始化它自己的不确定值。该成员正在提及一个这样的不确定值。