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

When to provide user-defined copy constructor and assignment operator?

本文关键字:构造函数 赋值运算符 复制 用户 定义 何时提      更新时间:2023-10-16

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

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

指针无疑是最明显的情况,但不是唯一的情况。

另一个示例是在 ctor 中打开数据库连接并在 dtor 中关闭它的类。副本 ctor 需要执行一些操作来复制数据库连接,因此副本与数据库的连接与原始数据库的连接分开关闭。

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

仅当您需要数据副本时,才应修复复制构造函数。

警告将是成员变量,这些变量是具有自己的复制构造函数的类,不能为您提供有关当时发生的事情的任何承诺。

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

对于流情况,此复制构造函数可能必须

a) 复制文件,

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

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

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

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

不太明显的是,一些不直接维护资源的类可能需要复制赋值:如果您希望复制赋值具有很强的异常安全性,则通常需要实现复制赋值。例如,假设您的类存储两个向量。生成的副本组合执行成员赋值。通常,成员分配是可以的。但是,如果对第二个向量的断言引发异常,则无法恢复原始状态!更好的副本组合如下所示:

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

由于swap()可以在不抛掷的情况下实现,因此这种性能具有很强的异常安全性。