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

时间:2015-04-20 22:19:03

标签: c++ language-lawyer

这是这堂课:

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

可以轻易复制? (至少clang似乎这么认为(live))

特别是

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

调用未定义的行为?

上下文:This answer [已删除,因为已证实错误]及其评论树。

1 个答案:

答案 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超过atomicmutex而不调用UB将是......让我们说的是严重问题。)另见N4460。< / p>