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

Pas*_* By 15 c++ language-lawyer

灵感来自这个问题.

struct E {};
E e;
E f(e);  // Accesses e?
Run Code Online (Sandbox Code Playgroud)

访问

读取或修改对象的值

空类具有隐式定义的复制构造函数

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

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

Oli*_*liv 3

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

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

struct E{
     E()=default;
     E(const E&){}
     };
E e;
e.~E();
E f(e);
Run Code Online (Sandbox Code Playgroud)

e是一个生命周期已结束但其存储空间仍被分配的对象。[basic.life]/6中描述了使用这样的左值可以做什么

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

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

  • 泛左值用于访问非静态数据成员或调用对象的非静态成员函数,或者

  • 泛左值被隐式转换([conv.ptr])为对基类类型的引用,或者

  • 泛左值用作 static_cast ([expr.static.cast]) 的操作数,除非最终转换为 cv char& 或 cv unsigned char&,或者

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

上面引用的任何一点都没有发生在E复制构造函数内,因此这个答案中的示例代码定义良好,这意味着无法访问被销毁对象的值。e所以在你的示例代码中无法访问。