首页 文章

我是否违反了三条规则?

提问于
浏览
3

我最近读过,Rule of three,我想知道我是否违反了它?

在我的GUI应用程序中,类如 MainFrameInterfaceCircuitBreadboard 等(类名称是指示性的)具有每个类的单个实例 . 在他们的构造函数中,我已经分配了一些资源(内存),我在析构函数中安全地释放了这些资源 .

所以我只定义了 destructor ,但没有 copy constructorassignment operator .

我确信我不需要它们,但我很好奇我是否违反了规则,我可以/应该做些什么来遵循它?

5 回答

  • 2

    三个规则是关于处理所有三巨头,但这并不一定意味着你想要的 . 要么你提供它们要么禁止它们 . 你不应该做的就是忽略它们 .


    所以我只定义了析构函数,但没有定义复制构造函数和复制运算符 . 我是否违反了三条规则?

    是的,你违反了规则 . 编译器将生成一个复制构造函数和复制赋值运算符,并且由于您在构造函数中分配内存并在析构函数中释放,因此这些副本将具有错误的语义:它们将复制指针,并且您将有两个类别于同一内存 . 赋值甚至不会释放旧内存,只是覆盖指针 .

    这是一个问题吗?

    如果像你所暗示的那样,你最好不要安全并宣布(并且不要随意调用它们) .

    在C 11中,您可以使用 = delete 语法:

    T(T const&) = delete; // no copy constructor
    T& operator=(T const&) = delete; // no copy assignment
    
  • 1

    它很大程度上取决于您的应用程序逻辑以及您如何向用户记录您的接口类 .

    通常情况下,一个好的程序员必须知道三个规则(如果你知道“复制和交换习语”,则为半个),而对于c 11(移动语义),则必须知道一个1/2 .

    如果您的类管理资源并且相同的类是可复制的(即复制ctor和assigment运算符未定义为私有),则通过编写自己的复制ctor和赋值运算符来进行深度复制非常重要 .

    但是如果你总是通过将它们作为REFERENCE传递给你的类来操作,那么最好将默认复制ctor和赋值运算符定义为private,这样即使你通过valy或者错误地复制,编译器也会警告你 .

  • 2

    您应该声明(但不实现)私有拷贝构造函数和赋值运算符 . 确保您没有实现这些功能 . 这将阻止任何类型的复制不应复制的类 .

  • 6

    是的,根据该定义,它确实违反了三条规则 .

    然而,这是一个“经验法则” . 一般准则 . 如果您不需要复制构造或赋值操作,请不要实现它们 . 其他人建议将它们声明为私有并将其定义为空 . 我更进一步说,甚至不定义它们 .

    如果您定义它们,那么您可能仍然可以调用空方法 . 相反,保留它们未定义,如果您尝试调用这些方法,则会收到链接器错误,因为找不到方法定义 . 支持运行时错误/不良行为的构建时错误 .

  • 1

    如果您不需要它,请不要遵循它 . 三个规则背后的动机是,当你需要一个析构函数时,通常是因为你需要做一些动态的解除分配 .

    如果你也进行解除分配,那么你也需要复制构造函数和赋值运算符 . 想象一下,你有一个指向某个东西的类:

    struct Foo
    {
        Foo() { ptr_ = new int; }
        ~Foo() { delete ptr_; }
        int* ptr_;
    };
    

    因为您没有定义复制构造函数和赋值运算符,所以每当复制 Foo 时,原始复制和复制都将使用指向同一 int 的指针;当原始文件或副本被销毁时,指针被释放,而另一个则无法使用数据 .

    Foo(cont Foo& other) {
        other.ptr_ = new int(*ptr_);
    }
    
    // Same for operator=
    

    如果您没有在构造函数/析构函数中进行任何动态分配,那么您很可能实际上不需要复制构造函数或赋值运算符(但不一定) .

相关问题