是否始终默认创建复制构造函数?

时间:2014-06-16 05:53:36

标签: c++ copy-constructor

据我所知,直到今天创建一个新类时会创建四个默认内容。 "默认构造函数","析构函数","复制构造函数"和"分配操作员"。但今天当我通过一篇C ++文章时,它说可能存在默认情况下不创建复制构造函数的情况。

  1. 这是真的吗?
  2. 如果是,在哪种情况下?
  3. 在这些情况下,如何通过值传递该类的实例?

2 个答案:

答案 0 :(得分:5)

1)是的,在某些情况下,默认情况下不会创建复制构造函数。

2)隐式声明的默认构造函数已删除的条件在 12.8中复制和移动类对象[class.copy]

12.8.7 是关于其他特殊成员函数的声明如何影响隐式声明的复制构造函数。每当类声明一个复制构造函数,一个移动构造函数或一个移动赋值运算符。如果它宣布其中任何一个,那么你不会得到一个隐含声明的。

  

...

     

7 如果类定义没有明确声明副本   构造函数,一个是隐式声明的。如果是类定义   声明一个移动构造函数或移动赋值运算符   隐式声明的复制构造函数被定义为已删除;除此以外,   它被定义为默认值(8.4)。后一种情况如果被弃用则弃用   class具有用户声明的复制赋值运算符或用户声明的   析构函数。

12.8.11 是关于数据成员和基类如何影响隐式声明的复制构造函数。实质上,如果类具有任何不可复制的数据成员或基类,则隐式声明的复制构造函数为delete d:

  

11 隐式声明的复制/移动构造函数是内联公共   同类的成员。 X类的默认复制/移动构造函数   如果X有:

,则定义为已删除(8.4.3)      

- 带有一个变体成员   非平凡的相应构造函数和X是类似联合的类,

     

- 类型为M(或其数组)的非静态数据成员,但不能   因为应用于M的重载分辨率(13.3)而被复制/移动   相应的构造函数,导致歧义或函数   从默认构造函数中删除或无法访问,

     

- 由于重载而无法复制/移动的直接或虚拟基类B.   决议(13.3),适用于B的相应构造函数,   导致歧义或被删除或无法访问的功能   来自默认构造函数,

     

- 任何直接或虚拟基类或   具有被删除或析构函数的类型的非静态数据成员   默认构造函数无法访问,

     

- 复制品   构造函数,rvalue引用类型的非静态数据成员,或

     

...

3)您可以声明和定义(通过提供实现或default复制构造函数,或移动复制构造函数,或两者。

答案 1 :(得分:0)

是的,这是正确的。例如,如果类的成员不可复制/可分配(例如,成员具有私有赋值运算符和私有复制构造函数),那么您将无法依赖包含类的默认复制构造函数。如果您希望在这些情况下包含类可以复制/分配,那么您需要明确定义这些操作。

话虽如此,在大多数情况下,你应该避免通过价值。在大多数情况下,您应该通过常量引用传递对象或传递对象的智能指针(例如std::unique_ptr)。传递值(以及执行不必要的复制量的任何代码)将产生比您能够重用现有实现的情况更低效的代码。此外,对于多态对象,按值传递会导致"切片" (该功能从运行时类型截断到正在复制对象的声明类型),因此当使用可能继承的任何数据类型进行操作时,按值传递特别危险且容易出错。

修改
为了澄清上面的内容......在传递const-reference和传递值方面,决定应该取决于对象的大小以及复制的成本。 Boost在&#34;呼叫特征中提供了一种便利的机制。 (call_traits<T>::param_type)根据对象的大小自动在值和const引用之间进行选择。在做出这个决定时,区分值类型(行为与基元类似的对象 - 例如,通过重载各种运算符,可复制,可分配,不能继承)和用户定义的多态有用也很有用。类型。每当你有一个声明虚方法的类型时,作为一般的经验法则,该对象应该通过引用或const引用传递,以避免我在上面提到的切片。

在传递智能指针方面,通常这是在转移或共享所有权时完成的(否则你通常应该只传递对相关对象的引用)。