为什么禁止使用复制构造函数和赋值运算符?

8
#undef GOOGLE_DISALLOW_EVIL_CONSTRUCTORS
#define GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeName)    \
   TypeName(const TypeName&);                           \
   void operator=(const TypeName&)

我正在阅读来自谷歌的开源代码。 为什么禁止使用复制构造函数和赋值运算符?


1
它们被称为“复制构造函数”和“赋值运算符”。没有所谓的赋值构造函数。 - Sjoerd
2
我会称它们为“构造函数”和“赋值运算符”,或者“拷贝构造函数”和“拷贝赋值运算符”。 - Johannes Schaub - litb
2
我不会称之为“邪恶”,这样会让它们带有负面色彩。只需像boost一样禁用它们:boost :: noncopyable - Martin York
3个回答

12

为防止类的实例被复制或分配,大多数类都不应允许复制。例如考虑一个BankAccount类 - 如果您为银行编写软件,如果创建帐户的副本并对这些不同的副本应用信用和借方,则他们将会感到非常不满意。


+1 .... @DumbCoder 如果你是那家银行软件的编码人员,这是可能的!! - KedarX
为什么不使用单例模式呢? @Neil Butterworth - MainID
4
单例模式意味着只能存在一个银行账户 - 大多数银行想要创建成千上万个账户。 - anon
大多数类不应该禁止复制,这种说法并不正确。顺便说一下,Google也是这样认为的。 - E. Vakili

8
复制构造函数和复制赋值运算符的问题在于,如果它们没有被显式声明,编译器会自动生成实现。这很容易导致意外问题。如果一个类有一个非平凡析构函数,它几乎总是需要为复制构造函数和复制赋值运算符提供自己的实现(这就是大三定律),因为默认的编译器生成的实现通常会做错事情。违反大三定律通常会导致错误,如数据成员的双重释放和内存破坏。这种错误经常发生,因为类的作者从未考虑过复制行为,并且因为消费者很容易无意中复制对象。除非类的作者实际上已经考虑过如何正确地复制该类的实例(或者除非该类具有平凡的析构函数),否则最好明确禁止复制以避免潜在问题。实现可复制性可以推迟到真正需要它的时候。

4
随着C++0x标准的推出,搭载移动构造器/赋值器这一新功能,这将成为“五大法则”的一部分! - David
1
@David:移动构造函数/移动赋值运算符将是选择性的(如果您省略它们,编译器不会为您生成它们)。 - jamesdlin
你说得没错,但如果你关心性能的话,也应该提供它们。 - David

1
如果您的类型包含指针或引用成员,或者它被复制没有语义意义(例如,它具有必须在析构函数中释放的资源句柄),那么禁用复制构造函数和赋值运算符是一个好的实践。在C++0x中(例如,在g++ 4.4或更高版本的-std=c++0x模式下),您可以声明它们已删除。在旧编译器中,您只需将它们声明为私有和未实现即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接