禁用复制构造函数


172

我有一堂课:

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 ( );

1
顺便说一句,这是一个带有继承规定的单身人士(已得到保护)吗?
R. Martinho Fernandes

我怀疑您的代码中是否每次都会创建不同的实例,我认为GetUniqueInstance()总是会引用同一对象。
Pratham Shah

Answers:


285

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

private:
    SymbolIndexer(const SymbolIndexer&);

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

SymbolIndexer(const SymbolIndexer&) = delete;

43
关于delete关键字,我想添加以下内容。在设计新类时,我目前的习惯是delete立即对复制构造函数和赋值运算符进行操作。我发现,根据上下文,它们基本上是不必要的,删除它们可以防止某些意外情况。如果发生可能需要复制代码的情况,请确定是否可以使用移动语义来完成。如果不希望这样做,请为复制ctor和赋值运算符提供一个实现。这是否是一个好方法,我会留给读者看。
pauluss86

1
@ pauluss86我喜欢您的方法,但由于我认为遵循此模式所花费的时间大于它所防止的错误所节省的时间,因此我不会完全致力于它。我只是在不确定时禁止复制。
托马什Zato -恢复莫妮卡

@ pauluss86这基本上就是Rust所做的:默认移动(默认移动和默认移动)。我认为非常有帮助。
卡皮丘

33

如果您不介意多重继承(毕竟还不错),则可以使用私有副本构造函数和赋值运算符编写简单的类,并进一步子类化:

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

不过,我不太确定此功能是否可以在每个编译器中使用。有一个相关的问题,但没有答案。

UPD:

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

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

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

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:

UPD:

Boost已经具有用于相同目的的类,我想它甚至是以类似的方式实现的。该类将被调用boost::noncopyable,并应按以下方式使用:

#include <boost/core/noncopyable.hpp>

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

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


那不应该NonAssignable(const NonAssignable &other);吗?
Troyseph 2015年

我认为如果将其更新为C ++ 11 delete关键字语法,此问题将获得更多认可。
托马什Zato -恢复莫妮卡

@TomášZato:想法是使副本构造函数和赋值运算符保持存在,但要私有。如果是delete他们,它将停止工作(我刚刚检查过)。
firegurafiku

@TomášZato:抱歉,我的测试方法有点错误。删除也可以。将在一分钟内更新答案。
firegurafiku '16

3
@Troyseph:const Class&Class const&是相当一致。对于指针,您甚至可以Class const * const键入。
firegurafiku '16

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.