禁止在C ++中复制构造和复制赋值

时间:2010-06-17 10:09:58

标签: c++

为了禁止复制构建和复制作业,我看过boost noncopyable课程,并在Google格式指南中看到了DISALLOW_COPY_AND_ASSIGN宏。有没有理由更喜欢其中一种技术,或者应该注意的任何细微差别?

6 个答案:

答案 0 :(得分:6)

我更喜欢在宏上提升不可复制,因为它不是宏,而且更容易(IMO)使用。

在实际代码中,我既没有使用它们也没有自己编写所需的两个声明。

但是,您可能感兴趣的一个细微差别是,当类本身尝试复制对象时,使用该宏或您自己的声明不会产生编译器错误(但是稍后无法链接)。 noncopyable但是在这种情况下也会发出编译器错误信号,因为它是基类,其函数声明为private,而不是类本身。

答案 1 :(得分:3)

我总是将复制构造函数和赋值运算符设为私有,而不实现:

  • 这可以防止有人在课堂外制作副本(会产生编译错误)
  • 这可以防止类本身也自己复制(会给出链接错误)

我还添加了一个明确的注释(就在复制构造函数和赋值运算符的原型之上),以表明我这样做是为了防止有人制作副本(作为对未来开发人员的提醒)。

在我看来,这个解决方案很明确,不依赖于外部库或宏,并且易于理解。

答案 2 :(得分:2)

基于尽可能避免继承的规则,我总是使用宏 - 在这种情况下是我自己的。当然,还有另一个关于避免使用宏的规则......

答案 3 :(得分:2)

我永远不会使用DISALLOW_COPY_AND_ASSIGN宏,因为你必须把它放在类声明的private部分。如果您(或维护代码的人)误将其放入public部分,该怎么办?问题在于,“DISALLOW_COPY_AND_ASSIGN”应该放在私有部分中并不明显:宏的名称似乎暗示它将不允许复制和赋值,而与您声明它的位置无关。 / p>

noncopyable基类完全避免了这个问题。

但是,最快,最易读和可移植的方法是在类的私有部分中显式声明构造函数。

答案 4 :(得分:0)

这两种技术[实际上]是相同的。一个使用宏来保存键入(您仍然需要将它放在通常放置代码的位置),另一个通过您扩展的基类提供设施。

避免使用宏是一件好事,但扩展一个类只是为了避免将复制构造函数放在类的私有部分,这似乎让读者感到困惑。

你有什么理由不在你班上做这两种方法吗?

答案 5 :(得分:0)

请考虑以下代码(受到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 ):

升压::不可复制

/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使用需要知道它的含义,如何使用,以及如何解析编译器错误;但是,它在代码中更加简洁。宏(谷歌/ Qt技术)需要宏定义(可能在其他一些标题中),以及如何使用它的知识;但是,编译器错误非常易读(与显式相同)。最后,显式技术最为明显,但可能需要程序员额外输入。