具有已删除的复制构造函数的类是否可以轻易复制?

Bau*_*gen 28 c++ language-lawyer

这个班是这样的:

class A {
  public:
    A() = default;
    A(const A&) = delete;
};
Run Code Online (Sandbox Code Playgroud)

平凡的可复制?(至少clang似乎这么认为(现场))

会特别的

A a,b;
std::memcpy(&a, &b, sizeof(A));
Run Code Online (Sandbox Code Playgroud)

调用未定义的行为?

上下文:这个答案 [删除,因为证明错误]加上其评论树.

T.C*_*.C. 28

更新:CWG 1734的拟议决议,目前处于"就绪"状态,将[class]/p6修改为:

一个简单的可复制类是一个类:

  • 其中每个复制构造函数,移动构造函数,复制赋值运算符和移动赋值运算符(12.8 [class.copy],13.5.3 [over.ass])要么被删除,要么是微不足道的,
  • 至少有一个未删除的复制构造函数,移动构造函数,复制赋值运算符或移动赋值运算符,以及
  • 有一个简单的,未删除的析构函数(12.4 [class.dtor]).

这使得类像

struct B {
    B() = default;
    B(const B&) = delete;
    B& operator=(const B&) = delete;
};
Run Code Online (Sandbox Code Playgroud)

不再是轻易复制的.(这类的类包括像std::atomic<T>和的同步原语std::mutex.)

但是,AOP中有一个隐式声明的,未删除的复制赋值运算符,它是微不足道的,所以它仍然可以轻易地复制.

CWG1734之前情况的原始答案保留在下面以供参考.


是的,有点违反直觉,它是可以轻易复制的.[类]/P6:

一个简单的可复制类是一个类:

  • 没有非平凡的复制构造函数(12.8),
  • 没有非平凡的移动构造函数(12.8),
  • 没有非平凡的副本赋值运算符(13.5.3,12.8),
  • 没有非平凡的移动赋值运算符(13.5.3,12.8),和
  • 有一个简单的析构函数(12.4).

[class.copy]/P12:

如果不是用户提供的,则类X的复制/移动构造函数是微不足道的,其参数类型列表等效于隐式声明的 参数类型列表,如果

  • class X没有虚函数(10.3),没有虚基类(10.1),和
  • 类X没有volatile限定类型的非静态数据成员,和
  • 选择复制/移动每个直接基类子对象的构造函数是微不足道的,并且
  • 对于类类型(或其数组)的X的每个非静态数据成员,选择复制/移动该成员的构造函数是微不足道的;

同样([class.copy]/p25):

如果类X不是用户提供的,则类X的复制/移动赋值运算符是微不足道的,其参数类型列表等效于隐式声明的 参数类型列表,如果

  • class X没有虚函数(10.3),没有虚基类(10.1),和
  • 类X没有volatile限定类型的非静态数据成员,和
  • 选择复制/移动每个直接基类子对象的赋值运算符是微不足道的,并且
  • 对于类型(或其数组)的X的每个非静态数据成员,选择复制/移动该成员的赋值运算符是微不足道的;

[class.dtor]/P5:

如果不是用户提供的析构函数是微不足道的,如果:

  • 析构函数不是virtual,
  • 它的所有直接基类都有琐碎的析构函数
  • 对于类类的所有非静态数据成员(或其数组),每个这样的类都有一个简单的析构函数.

[dcl.fct.def.default]/P5:

如果函数是用户声明的,并且在第一个声明中未明确默认或删除,则用户提供该函数.

实际上,这一直是委员会本身存在问题的根源,因为根据当前的定义atomic<T>(以及互斥和条件变量)可以轻易地复制.(很明显,允许某人memcpy超过atomicmutex不使用UB会......让我们说的是严重问题.)另见N4460.

  • @TC:一个可怕的决定.在删除构造函数的平凡性测试中,"构造函数选择复制/移动每个直接基类子对象是微不足道的"是什么意思?选择不会发生,没有选择*构造函数来复制/移动每个子对象*.它应该读取"已经选择的构造函数,是否已删除派生的构造函数"?但那么如果选择是不可能的,因为基础或成员构造函数被删除了呢?破碎,破碎,破碎. (3认同)