当我们有指针数据成员时,我们是否只需要编写一个复制构造函数和赋值运算符(因为否则当编译器生成的复制 ctor 执行浅复制时,两个指针可能指向同一个对象)?
如果我们所有的数据成员都分配在堆栈上,我们可以只依赖编译器定义的复制构造函数和赋值运算符吗?
当我们有指针数据成员时,我们是否只需要编写一个复制构造函数和赋值运算符(因为否则当编译器生成的复制 ctor 执行浅复制时,两个指针可能指向同一个对象)?
如果我们所有的数据成员都分配在堆栈上,我们可以只依赖编译器定义的复制构造函数和赋值运算符吗?
指针无疑是最明显的例子,但并不是唯一的例子。
另一个示例是在 ctor 中打开数据库连接并在 dtor 中关闭它的类。复制 ctor 需要做一些事情来复制数据库连接,因此副本与数据库的连接与原始连接分开关闭。
如果可行,请使用编译器定义的复制构造函数。浅拷贝通常更快,即使它们可能会处理指针地址而不是在某些情况下可能是您想要的指向数据。例如,您可能想要一个指向与代码的其他部分共享的纹理的指针。
只有当您需要数据的副本时,您才应该修复复制构造函数。
警告将是成员变量,它们是具有自己的复制构造函数的类,不能给你任何关于随后发生的事情的承诺。
如果类包含的基类或对象没有复制构造函数(即流),那么如果您希望您的类是可复制构造的,那么您必须实现复制构造函数。
对于流情况,此复制构造函数可能必须
a) 复制文件,
b)创建一个可以写入的新空文件,
c) 或保存流的地址,以便两个对象都可以写入。
最后一个选项是最复杂的,可能需要使用shared_ptr
.
通常,我喜欢将所有资源放入维护这些资源的类中,而这些资源维护者需要复制构造、复制分配和析构函数。根据资源,复制构造函数和复制赋值可能会被删除。
不那么明显的是,一些不直接维护资源的类可能需要复制分配:如果您希望复制分配具有强异常安全性,则通常需要实现复制分配。例如,假设您的类存储两个向量。生成的副本分配执行成员分配。通常,按成员分配很好。但是,如果对第二个向量的赋值抛出异常,就不可能恢复原来的状态!更好的副本分配如下所示:
T& T::operator= (T other) {
other. swap(*this);
return *this;
}
由于swap()
可以在不抛出的情况下实现,因此这种 imolementation 具有很强的异常安全性。