复制空对象是否涉及访问它

时间:2018-01-19 13:09:55

标签: c++ language-lawyer

受到this问题的启发。

struct E {};
E e;
E f(e);  // Accesses e?

access

  

读取或修改对象的值

空类有implicitly defined copy constructor

  

非联合类X的隐式定义的复制/移动构造函数执行其基础和成员的成员复制/移动。 [...]初始化顺序与用户定义构造函数中基数和成员的初始化顺序相同。设x或者是构造函数的参数,或者对于移动构造函数,是引用参数的xvalue。以适合其类型的方式复制/移动每个基本或非静态数据成员:

     
      
  • [...]基础或成员使用x的相应基础或成员进行直接初始化。
  •   

2 个答案:

答案 0 :(得分:3)

我认为标准中描述最准确执行访问的部分是[basic.life]。在本段中,将解释可以使用引用的引用或者指向超出其生命周期的对象的指针。授权使用此类实体的所有内容都不会执行对象值的访问,因为此值不存在(否则标准将不一致)。

所以我们可以采取一个更激烈的例子,如果这不是未定义的行为,那么在你的示例代码中无法访问e(相应于上面的推理):

struct E{
     E()=default;
     E(const E&){}
     };
E e;
e.~E();
E f(e);

此处e是一个对象,其生命周期已结束但仍保留其存储空间。 [basic.life]/6

中描述了使用这样的左值可以做些什么
  

类似地,在对象的生命周期开始之前但在对象将占用的存储之后已经分配,​​或者在对象的生命周期结束之后以及在重用或释放对象占用的存储之前,任何glvalue可以使用引用原始对象但仅限于有限的方式。对于正在构建或销毁的对象,请参阅[class.cdtor]。否则,这样的glvalue指的是已分配的存储([basic.stc.dynamic.deallocation]),而使用不依赖于其值的glvalue的属性是明确定义的。如果出现以下情况,该程序具有未定义的行为:

     
      
  • 左值到右值的转换([conv.lval])应用于这样的glvalue,

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

  •   
  • glvalue被隐式转换([conv.ptr])到对基类类型的引用,或

  •   
  • glvalue用作static_cast([expr.static.cast])的操作数,除非转换最终是cv char&或cv unsigned char&,或

  •   
  • glvalue用作dynamic_cast([expr.dynamic.cast])的操作数或typeid的操作数。

  •   

上面提到的所有内容都没有在E复制构造函数中发生,所以这个答案中的示例代码定义明确,这意味着无法访问被破坏对象的值。因此,您的示例代码中无法访问e

答案 1 :(得分:2)

我认为它不会访问该对象,但需要存在有效的对象。

E f(e);

这会调用E隐式定义的构造函数E::E(const E&)。显然这个构造函数的主体是空的(因为没有什么可做的)。因此,如果发生任何事情,它必须在参数传递期间发生,即在const E&e初始化期间发生。

不言而喻,此初始化不会修改e。现在,要读取e的值,必须进行左值到右值的转换。但是,该标准实际上表示在直接引用绑定 1 期间不会发生此转换。也就是说,不会执行读取。

但是,标准确实要求必须初始化引用以引用有效的对象或函数 2 (尽管这取决于CWG 453),所以像{{1将是不正确的。

1。这是通过非规范性地要求这种转换来完成的,并且由the non-normative note in [dcl.init.ref]进一步加强。

2。 [dcl.ref]