2011-04-18 121 views
20

有时需要禁止C++类中的拷贝构造函数,以便类变为“不可拷贝”。当然,operator=应该同时被禁止。在C++中禁止拷贝构造函数的最可靠方法是什么?

到目前为止,我见过两种方式来做到这一点。方法1是申报方法私有,并给它没有实现:

class Class { 
//useful stuff, then 
private: 
    Class(const Class&); //not implemented anywhere 
    void operator=(const Class&); //not implemented anywhere 
}; 

方式二是申报方法私有,并给它“空”的实施:

class Class { 
//useful stuff, then 
private: 
    Class(const Class&) {} 
    void operator=(const Class&) {} 
}; 

IMO第一个是更好的 - 即使有一些意想不到的原因导致从同一个类成员函数调用拷贝构造函数,稍后会出现链接器错误。在第二种情况下,直到运行时才会忽略这种情况。

第一种方法有什么严重的缺点吗?什么是更好的方式,如果有的话,为什么?

+4

http://www.boost.org/doc/libs/1_46_1/boost/noncopyable.hpp – dgnorton 2011-04-18 11:28:17

回答

16

第一种方法是Boost如何解决它(source code),据我所知,没有缺点。事实上,链接器错误是该方法的一大优点。您希望错误发生在链接时,而不是在您的客户端执行代码时突然崩溃。

如果您使用的是Boost,您可以节省一些键入。这确实与您的第一个例子:

#include <boost/utility.hpp> 

class Class : boost::noncopyable { 
// Stuff here 
} 
+7

虽然它可能是“Boost如何解决它”,但在基类中以这种方式解决它并在自己的类中自行完成之间仍然存在显着差异,因为基类方法更加自我记录,从而避免了某些人之后不小心将它添加到课程中,认为它没有被错误地实现。 – 2011-04-18 11:51:16

+0

这仍然是一个很好的情况,因为它可以让你在他们造成真正的伤害之前抓住那个人。当然,你不能指望小辈们知道这一点,但是他们不应该在没有复习的情况下做出这样的改变。 – MSalters 2011-04-18 12:41:55

+0

@Tony:我更喜欢boost替代方案(或者不能使用boost时的另一个自定义类)。它更容易理解,更具可读性,并且错误消息更好一些。 – 2011-04-18 14:54:51

25

第一个是更好

更妙的是C++0x 'delete' keyword

class Class { 
// useful stuff, then 
public: 
    Class(const Class&) = delete; 
    void operator=(const Class&) = delete; 
}; 
+6

@sehe:有了'delete',没有理由将它设为私有。事实上,它在公共界面中出现似乎更好,用户明智。 – 2011-04-18 12:01:49

+0

好点。更新 – sehe 2011-04-18 12:02:54

+0

@Matthieu在这种情况下使用'delete'是C++ 11;如果你不得不针对任何较老的编译器,甚至更多更新的编译器,你不能使用它。 – 2011-04-18 13:21:19

7

你总是可以从boost::noncopyable继承。

否则我从来没有见过理由2号比1号更好,因为它可以让你在朋友或类方法中“复制构造”一个​​对象,即使它不会真正创建对象的真实副本。

2

。在你的第一种方法不是缺点,我已经使用,为了使“不可复制”级..

3

至于其他的答案中建议别的东西,并没有真正试图回答这个问题,所以这里是我的尝试:

那么哪种方法更好?这取决于你如何定义禁止复制

如果您想防止其他人(只有非朋友类和功能)复制,同时允许朋友和会员功能复制,那么第二种方法是要走的路。

如果您想防止大家(朋友,非朋友,会员功能)复制,那么第一种方法是唯一正确的解决方案。

请注意,第二种方法不会阻止朋友和成员函数复制(即从调用复制函数)

1.如果你没有正确地在第二种情况下定义它们,然后复制将无法正常工作,如预期,但是这是一个不同的事情完全。但问题是第二种情况并不妨碍调用复制函数。编译器不会生成任何错误消息。

1

我个人认为你已经回答了你自己的问题,应该使用第一种方法。

如果你不希望它是可复制的,就像你说的那样会抛出链接错误。但是,如果你使用第二种方法,并且你最终偶然使用拷贝构造函数,它会编译并运行;你完全没有迹象表明不一致性来自何处,直到你打开一个调试器。或者如他所说,如果你可以使用现代编译器,使用C++ 11的'= delete'表示法。