据我所知,直到今天创建一个新类时会创建四个默认内容。 "默认构造函数","析构函数","复制构造函数"和"分配操作员"。但今天当我通过一篇C ++文章时,它说可能存在默认情况下不创建复制构造函数的情况。
答案 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引用传递,以避免我在上面提到的切片。
在传递智能指针方面,通常这是在转移或共享所有权时完成的(否则你通常应该只传递对相关对象的引用)。