繁体   English   中英

禁止使用C ++构建副本和分配副本

[英]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设置为BoostNoCopyMacroNoCopyExplicitNoCopy ,您会收到以下编译器错误(使用i686-apple-darwin11-llvm-g ++-4.2):

boost ::不可复制

/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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM