具有已删除的复制构造函数的类是否具有可复制性

Is a class with deleted copy-constructor trivially copyable?

本文关键字:是否 可复制 复制 删除 构造函数      更新时间:2023-10-16

这个类是吗

class A {
public:
A() = default;
A(const A&) = delete;
};

琐碎的可复制性?(至少叮当似乎是这么认为的(直播))

特别是

A a,b;
std::memcpy(&a, &b, sizeof(A));

调用未定义的行为?

上下文:这个答案[因为被证明是错的而被删除]加上它的评论树。

更新:目前处于"就绪"状态的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;
};

不再是微不足道的可复制。(这类类别包括像std::atomic<T>std::mutex这样的同步原语。)

然而,OP中的A有一个隐式声明的、未删除的复制分配运算符,这是微不足道的,因此它仍然是微不足道的可复制运算符。

以下是CWG1734之前情况的原始答案,以供参考。


是的,有点违反直觉,它是微不足道的可复制性。[class]/p6:

一个普通的可复制类是一个:

  • 没有非平凡的复制构造函数(12.8)
  • 没有非平凡的移动构造函数(12.8)
  • 没有非平凡的拷贝分配运算符(13.5.3、12.8)
  • 没有非平凡的移动分配运算符(13.5.3、12.8),以及
  • 有一个琐碎的析构函数(12.4)

[class.copy]/p12:

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

  • 类X没有虚拟函数(10.3),也没有虚拟基类(10.1),并且
  • 类X没有volatile限定类型的非静态数据成员,并且
  • 选择用于复制/移动每个直接基类子对象的构造函数是琐碎的,并且
  • 对于类类型(或其数组)的X的每个非静态数据成员,选择复制/移动该成员的构造函数为琐碎

类似([class.copy]/p25):

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

  • 类X没有虚拟函数(10.3),也没有虚拟基类(10.1),并且
  • 类X没有volatile限定类型的非静态数据成员,并且
  • 为复制/移动每个直接基类子对象而选择的赋值运算符是琐碎的,并且
  • 对于类类型(或其数组)的X的每个非静态数据成员,选择用于复制/移动该成员的赋值运算符为琐碎

[class.dtor]/p5:

如果析构函数不是用户提供的,并且如果:

  • 析构函数不是CCD_ 4
  • 其类的所有直接基类都有琐碎的析构函数,并且
  • 对于类类型(或其数组)的类的所有非静态数据成员,每个此类都有一个平凡的析构函数

[dcl.fct.default]/p5:

如果函数是用户声明的而不是显式的,则它是用户提供的在其第一次声明时默认或删除。

事实上,这一直是委员会自身问题的根源,因为在当前的定义下,atomic<T>(以及互斥和条件变量)是微不足道的可复制性。(很明显,允许某人在不调用UB的情况下通过atomicmutex进行memcpy是……有严重问题的。)另请参阅N4460。