在 C++ 中禁止复制构造函数的最可靠方法是啥?

Posted

技术标签:

【中文标题】在 C++ 中禁止复制构造函数的最可靠方法是啥?【英文标题】:What's the most reliable way to prohibit a copy constructor in C++?在 C++ 中禁止复制构造函数的最可靠方法是什么? 【发布时间】:2011-04-18 11:22:30 【问题描述】:

有时有必要在 C++ 类中禁止复制构造函数,以使类变为“不可复制”。当然operator=应该同时被禁止。

到目前为止,我已经看到了两种方法。方式一是将方法声明为私有,不给它实现:

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

方式2是声明方法私有,并给它“空”的实现:

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

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

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

【问题讨论】:

boost.org/doc/libs/1_46_1/boost/noncopyable.hpp 【参考方案1】:

第一个更好

更好的是C++0x 'delete' keyword:

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

【讨论】:

@sehe:delete 没有理由将其设为私有。事实上,将其显示在公共界面中似乎更好,对用户而言。 @Matthieu 在此上下文中使用 delete 是 C++11;如果您必须针对任何较旧的编译器,甚至是许多较新的编译器,则不能使用它。 @James Kanze C++0x 和 C++11 不一样吗?至少***是这么说的:en.wikipedia.org/wiki/C++11 @FractalizeR:它们是一样的。 C++0x 是“项目”名称。现在标准已经定稿,我们知道它应该在 2011 年发布,因此“新”标准应该是 C++11。 @Matthieu 那么@James 说了什么?我得到了他,所以他的意思是 delete 在这种情况下不是在 C++0x 中,而是在 C++11 中。【参考方案2】:

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

如果您使用的是 Boost,则可以节省一些打字时间。这与您的第一个示例相同:

#include <boost/utility.hpp>

class Class : boost::noncopyable 
// Stuff here

【讨论】:

虽然它可能是“Boost 如何解决它”,但在基类中以这种方式解决它与在您自己的类中自己解决它之间仍然存在显着差异,因为基类方法很多更多的自我记录,防止有人不小心在课堂上添加它,认为它是错误地未实现。 这仍然是一个不错的场景,因为它可以让你在对方造成真正伤害之前抓住他们。当然,你不能指望后辈知道这一点,但无论如何,他们不应该在未经审查的情况下做出这样的改变。 @Tony:我也更喜欢 boost 替代方案(或者当 boost 无法使用时,我更喜欢另一个自定义类)。它更容易理解,可读性更强,错误信息也更好一些。【参考方案3】:

您始终可以从boost::noncopyable 继承。

否则我从未见过原因 2 比 1 更好,因为它允许您在朋友或类方法中“复制构造”对象,即使它实际上不会创建对象的真实副本。

【讨论】:

【参考方案4】:

由于其他答案暗示了其他东西,并没有真正尝试回答这个问题,所以这是我的尝试:

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

如果你想防止其他人(仅限非朋友类和函数)复制同时允许朋友和成员函数复制,那么第二种方法是要走的路。

如果您想防止每个人(朋友、非朋友、成员函数)复制,那么第一种方法是唯一正确的解决方案。

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

1.如果您在第二种情况下没有正确定义它们,那么复制将无法按预期工作,但这完全是另一回事。但关键是第二种情况并不能阻止调用复制函数。编译器不会产生任何错误信息。

【讨论】:

【参考方案5】:

您的第一种方法没有缺点,我一直在使用它来制作“不可复制”类..

【讨论】:

【参考方案6】:

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

如果您根本不希望它可复制,正如您所说,它将引发链接器错误。但是,如果您使用第二种方法并且您最终意外使用了复制构造函数,它将编译并运行;在您打开调试器之前,您绝对不会知道不一致的来源。或者如 sehe 所说,如果您可以使用现代编译器,请使用 C++11 的 '= delete' 表示法。

【讨论】:

以上是关于在 C++ 中禁止复制构造函数的最可靠方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

c++ 复制构造函数和析构函数

C++在构造函数中调用最终的虚函数

C++ 中类的默认成员函数的问题(构造函数、析构函数、运算符 =、复制构造函数)(默认 ctor、dtor、复制 ctor)

C++在单继承多继承虚继承时,构造函数复制构造函数赋值操作符析构函数的执行顺序和执行内容

[C++]8.3-8.4 析构函数,复制构造函数(深拷贝)(作业)

C++类的成员函数:构造析构拷贝构造运算符重载