[英]Prohibiting copy construction and copy assignment in C++
为了禁止复制构造和复制分配,我看到了boost不可复制类,并在Google样式指南中显示了DISALLOW_COPY_AND_ASSIGN宏。 是否有任何理由比其中一种更喜欢一种技术,或者应该意识到任何细微的差异?
与宏相比,我更喜欢boost noncopyable,因为它不是宏,并且更易于使用(IMO)。
在实际代码中,我都不使用它们,而是编写自己需要的两个声明。
但是,您可能感兴趣的一个细微差别是,当类本身尝试复制对象时(但稍后无法链接),使用该宏或您自己的声明不会产生编译器错误。 但是,不可noncopyable
也会在这种情况下发出编译器错误信号,因为具有声明为私有功能的是基类,而不是类本身。
我总是将复制构造函数和赋值运算符设为私有,而没有实现:
我还添加了一条清晰的注释(仅在复制构造函数和赋值运算符的原型上方),以表明我这样做是为了防止有人进行复制(以提醒将来的开发人员)。
我认为,这种解决方案很明确,不依赖于外部库或宏,并且易于理解。
基于尽可能避免继承的规则,我总是使用宏-在这种情况下,我是自己的。 当然,还有另一个规则,就是避免使用宏...
我永远不会使用DISALLOW_COPY_AND_ASSIGN
宏,因为您必须将其放在类声明的private
部分中。 如果您( 或维护代码的人 )错误地将其放入public
部分该怎么办? 问题在于,根本没有将“ DISALLOW_COPY_AND_ASSIGN
”放在私有部分中:宏的名称似乎暗示着它将独立于您声明的位置而禁止复制和分配。
noncopyable
基类完全避免了此问题。
但是,最快,最易读和可移植的方法是在类的私有部分中显式声明构造函数。
两种技术实际上是相同的。 一个使用宏保存类型(您仍然必须将其放置在通常放置代码的位置),另一个使用宏通过扩展的基类提供便利。
避免使用宏是一件好事,但是扩展类只是为了避免将复制构造函数放在类的私有部分中,这会使读者感到困惑。
您有什么理由不只是在您的类中做这两种方法?
考虑以下代码(在boost网站上受到noncopyable_test.cpp的启发):
#include <boost/noncopyable.hpp>
#include <iostream>
using namespace std;
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
class BoostNoCopy : boost::noncopyable {
public:
BoostNoCopy() { cout << "BoostNoCopy failed." << endl; }
};
class MacroNoCopy {
public:
MacroNoCopy() { cout << "MacroNoCopy failed." << endl; }
private:
DISALLOW_COPY_AND_ASSIGN(MacroNoCopy);
};
class ExplicitNoCopy {
public:
ExplicitNoCopy() { cout << "ExplicitNoCopy failed." << endl; }
private:
ExplicitNoCopy(const ExplicitNoCopy&);
void operator=(const ExplicitNoCopy&);
};
int main() {
typedef BoostNoCopy NotCopyable;
NotCopyable a;
NotCopyable b(a);
a = b;
return 0;
}
通过将main()中的typedef设置为BoostNoCopy
, MacroNoCopy
或ExplicitNoCopy
,您会收到以下编译器错误(使用i686-apple-darwin11-llvm-g ++-4.2):
/usr/local/include/boost/noncopyable.hpp: In copy constructor ‘BoostNoCopy::BoostNoCopy(const BoostNoCopy&)’:
/usr/local/include/boost/noncopyable.hpp:27: error: ‘boost::noncopyable_::noncopyable::noncopyable(const boost::noncopyable_::noncopyable&)’ is private
main.cpp:9: error: within this context
main.cpp: In function ‘int main()’:
main.cpp:33: note: synthesized method ‘BoostNoCopy::BoostNoCopy(const BoostNoCopy&)’ first required here
/usr/local/include/boost/noncopyable.hpp: In member function ‘BoostNoCopy& BoostNoCopy::operator=(const BoostNoCopy&)’:
/usr/local/include/boost/noncopyable.hpp:28: error: ‘const boost::noncopyable_::noncopyable& boost::noncopyable_::noncopyable::operator=(const boost::noncopyable_::noncopyable&)’ is private
main.cpp:9: error: within this context
main.cpp: In function ‘int main()’:
main.cpp:34: note: synthesized method ‘BoostNoCopy& BoostNoCopy::operator=(const BoostNoCopy&)’ first required here
main.cpp: In function ‘int main()’:
main.cpp:18: error: ‘MacroNoCopy::MacroNoCopy(const MacroNoCopy&)’ is private
main.cpp:33: error: within this context
main.cpp:18: error: ‘void MacroNoCopy::operator=(const MacroNoCopy&)’ is private
main.cpp:34: error: within this context
main.cpp: In function ‘int main()’:
main.cpp:25: error: ‘ExplicitNoCopy::ExplicitNoCopy(const ExplicitNoCopy&)’ is private
main.cpp:33: error: within this context
main.cpp:26: error: ‘void ExplicitNoCopy::operator=(const ExplicitNoCopy&)’ is private
main.cpp:34: error: within this context
即使您可以解析使用boost :: noncopyable时给出的编译器错误,也绝对需要花费更长的时间。 对于宏和显式情况,错误非常明显。
因此,似乎需要权衡的是,boost :: noncopyable的使用要求了解其含义,用法以及解析编译器错误的方法。 但是,它在代码中更加简洁。 宏(Google / Qt技术)需要宏定义(可能在其他标头中),以及如何使用它的知识; 但是,编译器错误很容易读取(与显式错误相同)。 最后,显式技术最为明显,但可能需要程序员额外键入。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.