![]() |
1
66
编译器生成的复制构造函数执行成员级复制。有时这还不够。例如:
在这种情况下,从成员的角度复制
|
![]() |
2
42
我有点恼火的是
这条规则非常简单:
但是,您应该遵循一个更一般的指导原则,这源于编写异常安全代码的需要:
在这里
如果发生了什么
处理这种情况的正确方法是使用适当的类而不是原始指针。
使用相同的构造函数实现(或实际使用
因此,
我不知道你的情况,但我觉得我的比较容易;) |
![]() |
3
28
我可以从我的实践中回忆起,当必须处理显式声明/定义复制构造函数时,我会想到以下情况。我把这些案件分为两类
正确性/语义在本节中,我将说明声明/定义复制构造函数对于使用该类型的程序的正确操作是必要的。 在阅读本节之后,您将了解允许编译器自己生成复制构造函数的几个陷阱。因此,作为 seand 注意到他的 answer ,关闭新类的可复制性是安全的,并且 故意地 以后需要时启用。 如何在C++ 03中制作一个不可复制的类声明一个私有的复制构造函数,不要为它提供实现(这样,即使该类型的对象是在类自己的作用域或由它的朋友复制的,构建也会在链接阶段失败)。 如何使类在C++ 11或更新中不可复制
用声明复制构造函数
浅拷贝与深拷贝这是最容易理解的情况,实际上是其他答案中提到的唯一一个。 shaprtooth 有 covered 很好。我只想补充一下,应该由对象独占的深度复制资源可以应用于任何类型的资源,其中动态分配的内存只是一种类型。如果需要,深度复制对象也可能需要
自注册对象考虑一个类,其中所有对象(不管它们是如何构造的)都必须以某种方式注册。一些例子:
此类自注册操作必须由该类型的任何构造函数执行,复制构造函数也不例外。 具有内部交叉引用的对象有些对象可能具有不平凡的内部结构,在其不同的子对象之间具有直接的交叉引用(事实上,仅一个这样的内部交叉引用就足以触发这种情况)。编译器提供的复制构造函数将破坏内部 对象内 关联,将它们转换为 对象间 联想。 一个例子:
仅允许复制符合特定条件的对象在某些状态(例如,默认构造状态)下,可能存在对象可以安全复制的类,并且 不 否则可以安全复制。如果我们希望允许安全复制对象,那么——如果是防御性编程——我们需要在用户定义的复制构造函数中进行运行时检查。 不可复制的子对象有时,应该是可复制的类会聚合不可复制的子对象。 通常,这种情况发生在具有不可观测状态的对象上(这种情况将在下面的“优化”部分中更详细地讨论)。编译器只是帮助识别这种情况。 准可复制子对象应该是可复制的类可以聚合准可复制类型的子对象。准可复制类型不提供严格意义上的复制构造函数,但具有另一个允许创建对象概念副本的构造函数。使类型具有准可复制性的原因是,对于类型的复制语义没有完全一致的时候。
然后,最终决定权留给该类型的用户——在复制对象时,他们必须(通过其他参数)显式地指定要复制的方法。 在编程的非防御方法中,也可能同时存在常规复制构造函数和准复制构造函数。在绝大多数情况下,应采用单一复制方法,而在极少但理解良好的情况下,应采用其他复制方法,这是合理的。那么编译器就不会抱怨它不能隐式地定义复制构造函数;记住并检查该类型的子对象是否应该通过准复制构造函数进行复制是用户的唯一责任。 不要复制与对象标识强相关的状态在极少数情况下,对象的一个子集 可观察的 国家可以构成(或被视为)对象身份不可分割的一部分,不应转移到其他对象(尽管这可能有些争议)。 实例:
在这种情况下,复制构造函数必须跳过复制相应的子对象。 强制复制构造函数的正确签名编译器提供的复制构造函数的签名取决于哪些复制构造函数可用于子对象。如果至少有一个子对象没有 实拷贝构造函数 (通过常量引用获取源对象),但具有 正在改变复制构造函数 (通过非常量引用获取源对象)那么编译器将别无选择,只能隐式声明,然后定义一个可变的复制构造函数。
现在,如果子对象类型的“变化的”复制构造函数实际上没有改变源对象(并且只是由一个不知道
书面副本(COW)在构造时,必须对直接引用其内部数据的Cow容器进行深度复制,否则它可能会充当引用计数句柄。
优化在以下情况下,出于优化考虑,您可能需要/需要定义自己的复制构造函数: 复制过程中的结构优化考虑一个支持元素删除操作的容器,但可以通过简单地将删除的元素标记为已删除,然后在以后回收其槽来实现。当复制这样一个容器时,压缩剩余的数据而不是保留“已删除”的槽是有意义的。 跳过复制不可见状态对象可能包含不属于其可观测状态的数据。通常,这是在对象的生命周期中积累的缓存/内存化数据,以加速对象执行的某些较慢的查询操作。跳过复制该数据是安全的,因为它将在何时(如果!)执行相关操作。复制此数据可能是不合理的,因为如果对象的可观察状态(从中派生缓存数据)通过改变操作进行了修改(如果我们不打算修改对象,那么为什么要创建一个深度副本?),则复制可能会很快失效。 只有当辅助数据比代表可观测状态的数据大时,这种优化才是合理的。 禁用隐式复制
C++允许通过声明复制构造函数来禁用隐式复制。
托多斯
|
![]() |
4
6
如果您有一个动态分配内容的类。例如,您将一本书的标题存储为char*并将标题设置为new,copy将不起作用。
您必须编写一个复制构造函数,
|
![]() |
5
2
当对象按值传递、按值返回或显式复制时,调用复制构造函数。如果没有复制构造函数,C++将创建一个默认拷贝构造器,它创建浅拷贝。如果对象没有指向动态分配内存的指针,那么Shallow Copy将执行此操作。 |
![]() |
6
0
通常最好禁用copy ctor,operator=除非类特别需要它。这可以防止效率低下,例如在预期引用时按值传递参数。另外,编译器生成的方法可能无效。 |
![]() |
7
-1
让我们考虑下面的代码片段:
只是想和大家分享这些知识,尽管你们大多数人已经知道了。 干杯。。。 快乐编码!!!! |
![]() |
AstralHex · 矩阵乘法代码工作不正常 4 月前 |
![]() |
Fishie · 作为类成员的智能指针是否仍然自动释放?[关闭] 5 月前 |
![]() |
Die4Toast · 递归调用成员箭头运算符-> 5 月前 |
![]() |
Anka Hanım · 关于结构和动态数组地址的问题 5 月前 |