这是这堂课:
class A {
public:
A() = default;
A(const A&) = delete;
};
可以轻易复制? (至少clang似乎这么认为(live))
特别是
A a,b;
std::memcpy(&a, &b, sizeof(A));
调用未定义的行为?
上下文:This answer [已删除,因为已证实错误]及其评论树。
答案 0 :(得分: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;
};
不再是轻易复制的。 (此类的类包括同步原语,如std::atomic<T>
和std::mutex
。)
但是,OP中的A
有一个隐式声明的,未删除的复制赋值运算符,这是非常简单的,所以它仍然是可以复制的。
CWG1734之前情况的原始答案保留在下面以供参考。
是的,有些违反直觉,它是可以轻易复制的。 [类] / 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:
如果析构函数不是用户提供的,并且如果:
,则析构函数很简单
- 析构函数不是
virtual
,- 其类的所有直接基类都有简单的析构函数,
- 对于类类的所有非静态数据成员(或其数组),每个类都有一个小问题 析构函数。
[dcl.fct.def.default] / P5:
如果函数是用户声明的而非显式的,则用户提供 在第一份声明中默认或删除。
实际上,这已经是a source of problems for the committee itself,因为根据当前的定义atomic<T>
(以及互斥和条件变量)将是可以轻易复制的。 (很明显,允许某人memcpy
超过atomic
或mutex
而不调用UB将是......让我们说的是严重问题。)另见N4460。< / p>