2012-02-04 58 views
3

我最近读,Rule of three,我想知道我是否违反了它?我违反三条规则吗?

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

所以我只定义了析构函数,但不拷贝构造函数赋值运算符

我确定我不需要它们,但是我很好奇如果我违反规则,以及我能做什么来遵循它?

回答

6

三条规则约交易与所有三巨头,但这并不一定意味着如果你不想要,你必须定义它们。要么你提供他们,要么你禁止他们。你不应该做的就是忽略它们。


所以我只定义了析构函数,而不是拷贝构造函数和复制操作。
我违反了三条法则吗?

是的,你违反了规则。编译器将生成一个拷贝构造函数和拷贝赋值操作符,并且由于您在构造函数中分配了内存并在析构函数中释放,所以这些拷贝将具有错误的语义:它们将复制指针,并且将有两个类别别名相同的内存。该分配甚至不会释放旧的内存,而只是覆盖指针。

这是问题吗?

如果,像你这样的暗示,你不进行复印或分配到这些类的实例,不会出错。但是,最好保证安全,并且声明(甚至不要打扰)复制构造函数和复制赋值运算符private,所以不会意外调用它们。

在C++ 11可以使用= delete语法来代替:

T(T const&) = delete; // no copy constructor 
T& operator=(T const&) = delete; // no copy assignment 
+0

第一个说法解决了我的疑问。 '= delete'看起来是一个很好的解决方案,只是告诉我这两个原型是否应该是私有的(除了'= delete') – 2012-02-04 07:22:03

+0

@Vinayak:如果你使用'= delete',那么它们是没有关系的是公共的还是私人的。 – 2012-02-04 07:25:52

+0

+1为所有伟大的答案! – 2012-02-04 07:27:33

2

您应该声明(但不执行)的私人拷贝构造函数和赋值操作符。确保你没有实现这些功能。这将防止任何类型的不应复制的类的复制。

+2

非空功能。你应该声明它们是私有的,永远不要指定任何实现。如果您的代码最终复制/分配对象,这将保证失败。 – StilesCrisis 2012-02-04 07:15:23

+0

请关注@StilesCrisis,关注。相应地编辑你的答案 – 2012-02-04 07:28:51

+0

我只记得我现在可以编辑。我修复了它。 – StilesCrisis 2012-02-04 07:35:30

1

是的,它确实违反了三定义的规则。

然而,这是一个“经验法则”。一般指导原则。如果您不需要复制构建或分配操作,请不要实施它们。其他人则建议宣布它们是私人的,并将它们定义为空的。我会更进一步说甚至没有定义它们。

如果你定义它们,那么你仍然可能会调用空方法。相反,将它们留在未定义的位置,如果您尝试调用这些方法,您将收到链接器错误,因为找不到方法定义。在运行时错误/不希望的行为上赞成构建时错误。

2

这很大程度上取决于您的应用程序逻辑以及您如何将用户的接口类记录在文件中。

正常情况下,一个好的C++程序员必须知道三个规则(如果你知道“复制和交换习惯用法”,那么你应该知道一半),在C++ 11中移动语义)。

如果您的班级管理资源,并且如果同一班级是可复制的(即复制ctor和assigment操作员没有定义为私人),那么通过编写您自己的copy ctor和assignment operator来进行深层复制非常重要。

但是,如果你总是把你的课程作为REFERENCE传给他们,那么最好定义一个默认的copy ctor和赋值运算符为private,这样即使你通过valy或错误地复制,编译器也会警告你。

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= 

如果你没有在你的构造函数/析构函数做任何动态分配,有你实际上并不需要一个拷贝构造函数或赋值操作符(但不一定是)一个很好的机会。

相关问题