何时提供用户定义的复制构造函数和赋值运算符?

时间:2013-10-26 17:09:46

标签: c++ memory-management copy-constructor deep-copy

当我们有指针数据成员时,我们只需要编写一个复制构造函数和赋值运算符(因为否则当编译器生成的复制文件执行浅复制时,两个指针可能指向同一个对象)?

如果我们的所有数据成员都在堆栈上分配,我们可以依赖编译器定义的复制构造函数和赋值运算符吗?

4 个答案:

答案 0 :(得分:4)

指针毫无疑问是最明显的情况,但并非真正唯一的情况。

另一个例子是在ctor中打开数据库连接并在dtor中关闭它的类。复制ctor需要做一些事情来复制数据库连接,因此复制到数据库的连接将与​​原始连接分开关闭。

答案 1 :(得分:1)

如果有效,请使用编译器定义的复制构造函数。 浅拷贝通常更快,即使它们可以处理指针地址而不是在某些情况下可能是你想要的指向数据。例如,您可能需要一个指向与代码其他部分共享的纹理的指针。

只有在需要数据副本时才应修复复制构造函数。

警告是成员变量,这些变量是具有自己的副本构造函数的类,不能就当时发生的事情给出任何承诺。

答案 2 :(得分:0)

如果类所包含的基类或对象没有复制构造函数(即流),那么如果您希望您的类可以复制构造,那么您必须实现一个复制构造函数。

对于流案例,此拷贝构造函数可能必须

a)复制文件,

b)创建一个可以写入的新空文件,

c)或保存流的地址,以便两个对象都可以写入。

最后一个选项是最复杂的,可能需要使用shared_ptr

答案 3 :(得分:0)

通常,我喜欢将所有资源都放在维护这些资源的类中,这些tesource维护者需要一个复制构造,复制赋值和析构函数。根据资源的不同,可能会删除复制构造函数和复制分配。

不显而易见的是,某些不直接维护资源的类可能需要复制分配:如果您希望复制分配具有强烈的异常安全性,则通常需要实现复制分配。例如,假设您的类存储两个向量。生成的副本分配执行成员分配。通常,成员分配是好的。但是,如果对第二个向量的赋值抛出异常,则无法恢复原始状态!更好的副本分配看起来像这样:

T& T::operator= (T other) {
    other. swap(*this);
    return *this;
}

由于swap()可以在不抛出的情况下实现,因此这种错误安全性非常强烈。