我应该何时定义自己的复制运算符和赋值运算符 我在阅读第5条中的有效C++,它提到了两个我必须自己定义拷贝赋值操作符的例子。case是一个包含常量和引用成员的类

我应该何时定义自己的复制运算符和赋值运算符 我在阅读第5条中的有效C++,它提到了两个我必须自己定义拷贝赋值操作符的例子。case是一个包含常量和引用成员的类,c++,C++,我写这封信的目的是想问,我必须定义自己的复制构造函数和赋值运算符的一般规则或情况是什么 我还想知道何时必须定义自己的构造函数和析构函数 非常感谢 默认复制构造函数通常会导致两个对象“指向”一个公共内存块。这是因为默认复制构造函数所做的全部工作都是按成员分配。因此,如果您有一个指针成员,这可能会给您带来麻烦 CClass::CClass(const CClass& src) { // these two point to the same place in m

我写这封信的目的是想问,我必须定义自己的复制构造函数和赋值运算符的一般规则或情况是什么

我还想知道何时必须定义自己的构造函数和析构函数


非常感谢

默认复制构造函数通常会导致两个对象“指向”一个公共内存块。这是因为默认复制构造函数所做的全部工作都是按成员分配。因此,如果您有一个指针成员,这可能会给您带来麻烦

    CClass::CClass(const CClass& src)
    {
       // these two point to the same place in memory now
       // you really aught to allocate new memory
       m_ptr = src.m_ptr;

       // not a big deal for members that aren't "pointing" elsewhere
       // this copy works great
       m_int = src.m_int;
    }
基本上,您不希望最后出现两个实例“指向”内存中的同一个位置的情况。当指针作为指向动态分配内存的成员时,可能会发生这种情况。引用也可能发生这种情况,两者都引用类本身之外的内容。这可能发生在文件句柄中,您可能需要复制/重新打开新文件

事实上,后一种情况可能是最容易概念化的。假设你的2个C++对象都有一个日志文件。如果没有正常运行的复制构造函数,它们可能都会登录到同一个文件。如果在类析构函数中,文件被关闭,会发生什么?那么,第二C++对象将有从他下面关闭的日志文件。一种解决方案是创建一个副本构造函数,为新构造的实例创建一个新文件。所以当第一C++对象消失时,它不会将第二C++对象的日志文件带到它。它们有两个独立的日志文件,不能相互干扰


这个例子可以扩展到动态内存。如果没有复制构造函数,您将只有两个指针指向同一地址。如果一个的析构函数删除了该内存,另一个可能没有意识到它指向的内存已经消失。同样重要的是,您可能不希望一个对象写入另一个对象的成员:)。

在以下情况下,您必须创建自己的复制构造函数和赋值运算符(通常也是默认构造函数):

  • 您希望复制或指定对象,或将其放入标准容器中,如
    vector
  • 默认的复制构造函数和赋值运算符不会执行正确的操作
考虑以下代码:

class A; // defined elsewhere
class B {
private:
    A *my_very_own_a;
};
如果让自动复制构造函数复制a
B
,它将跨多个位置复制
a*
指针值,以便副本指向与原始实例相同的
a
实例。但是这个类的部分设计是每个
B
都有自己的
A
,因此自动复制构造函数破坏了这个契约。因此,您需要编写自己的复制构造函数,它将为要指向的新
B
创建一个新的
a

然而,考虑这种情况:

class A; // defined elsewhere
class B {
private:
    A *shared_reference_to_a;
};
这里,每个
B
都包含一个指向
a
的指针,但是类契约并不要求每个
B
都有一个唯一的
a
。因此,自动复制构造函数可能在这里做正确的事情

请注意,这两个示例是相同的代码,但具有不同的设计意图

第一种情况的示例可能是
B
==对话框,
A
==按钮。如果创建对话框的副本,它可能也需要所有内容的副本

第二个示例可能是
B
==对话框,
A
==对窗口管理器的引用。如果复制对话框,则该副本可能与原始对话框存在于同一个窗口管理器中。

据我所知(并采取行动)-另一个良好做法(不要在此处撤回其他答案)是遵循“三个规则”: