禁用复制构造函数

Disable copy constructor

提问人:Humble Debugger 提问时间:5/21/2011 最后编辑:DharmanHumble Debugger 更新时间:5/29/2022 访问量:182878

问:

我有一个班级:

class SymbolIndexer {
protected:
  SymbolIndexer ( ) { }

public:
  static inline SymbolIndexer & GetUniqueInstance ( ) 
  { 
    static SymbolIndexer uniqueinstance_ ;
    return uniqueinstance_ ; 
  }
};

我应该如何修改它以禁用如下代码:

SymbolIndexer symbol_indexer_ = SymbolIndexer::GetUniqueInstance ( );

并且只允许以下代码:

SymbolIndexer & ref_symbol_indexer_ = SymbolIndexer::GetUniqueInstance ( );
C++ 复制构造函数

评论

1赞 R. Martinho Fernandes 5/21/2011
顺便说一句,这是一个有继承条款的单例(受到保护)吗?
0赞 Pratham Shah 4/4/2020
我怀疑您的代码是否会在每次创建不同的实例时,我认为 GetUniqueInstance() 将始终引用相同的对象。

答:

4赞 Aaron Klotz 5/21/2011 #1

设为私有。如果要分配给引用,则不是复制。SymbolIndexer( const SymbolIndexer& )

347赞 R. Martinho Fernandes 5/21/2011 #2

您可以将复制构造函数设为私有,并且不提供任何实现:

private:
    SymbolIndexer(const SymbolIndexer&);

或者在 C++ 11 中,明确禁止它:

SymbolIndexer(const SymbolIndexer&) = delete;

评论

66赞 pauluss86 2/1/2014
关于关键字,我想添加以下内容。我目前在设计新类时的习惯习惯是立即复制构造函数和赋值运算符。我发现,根据上下文,它们大多是不必要的,删除它们可以防止一些意外行为的情况。如果出现可能需要复制 ctor 的情况,请确定是否可以使用移动语义来完成。如果这是不可取的,请为 copy ctor 和 assignment 运算符(!)提供实现。这是否是一个好方法,我将留给读者。deletedelete
1赞 Tomáš Zato 1/14/2016
@pauluss86我喜欢你的方法,但我不会完全致力于它,因为我认为遵循这种模式所花费的时间大于它所防止的错误所节省的时间。只要不确定,我就禁止复制。
0赞 Kapichu 12/31/2016
@pauluss86 这基本上就是 Rust 所做的:默认移动(和默认 const)。在我看来非常有帮助。
48赞 firegurafiku 3/19/2014 #3

如果你不介意多重继承(毕竟这还不错),你可以用私有复制构造函数和赋值运算符编写简单的类,并额外对其进行子类化:

class NonAssignable {
private:
    NonAssignable(NonAssignable const&);
    NonAssignable& operator=(NonAssignable const&);
public:
    NonAssignable() {}
};

class SymbolIndexer: public Indexer, public NonAssignable {
};

对于 GCC,这将给出以下错误消息:

test.h: In copy constructor ‘SymbolIndexer::SymbolIndexer(const SymbolIndexer&)’:
test.h: error: ‘NonAssignable::NonAssignable(const NonAssignable&)’ is private

不过,我不太确定这是否适用于每个编译器。有一个相关的问题,但还没有答案。

更新:

在 C++11 中,您还可以编写如下类:NonAssignable

class NonAssignable {
public:
    NonAssignable(NonAssignable const&) = delete;
    NonAssignable& operator=(NonAssignable const&) = delete;
    NonAssignable() {}
};

该关键字可防止成员被默认构造,因此不能在派生类的默认构造成员中进一步使用它们。尝试分配在 GCC 中出现以下错误:delete

test.cpp: error: use of deleted function
          ‘SymbolIndexer& SymbolIndexer::operator=(const SymbolIndexer&)’
test.cpp: note: ‘SymbolIndexer& SymbolIndexer::operator=(const SymbolIndexer&)’
          is implicitly deleted because the default definition would
          be ill-formed:

更新:

Boost 已经有一个用于相同目的的类,我猜它甚至以类似的方式实现。该类称为 boost::noncopyable,旨在按如下方式使用:

#include <boost/core/noncopyable.hpp>

class SymbolIndexer: public Indexer, private boost::noncopyable {
};

如果您的项目政策允许,我建议您坚持使用 Boost 的解决方案。有关更多信息,另请参阅另一个boost::noncopyable 相关的问题

评论

0赞 Troyseph 11/6/2015
那不应该是吗?NonAssignable(const NonAssignable &other);
0赞 Tomáš Zato 1/14/2016
我认为如果这个问题更新为 C++11 关键字语法,它会得到更多的赞成票。delete
0赞 firegurafiku 1/14/2016
@TomášZato:这个想法是保持复制构造函数和赋值运算符的存在,但私有。如果你他们,它就会停止工作(我刚刚检查过)。delete
0赞 firegurafiku 1/14/2016
@TomášZato:啊,对不起,我的测试方法有点不对。删除也有效。将在一分钟内更新答案。
3赞 firegurafiku 1/14/2016
@Troyseph:而且都差不多。对于指针,您甚至可以键入。const Class&Class const&Class const * const