为什么我要删除移动构造函数并在单例中移动赋值运算符?

vso*_*tco 16 c++ singleton move-semantics c++11

我有以下Singleton策略类实现:

template <typename T>
class Singleton
{
    Singleton(){}; // so we cannot accidentally delete it via pointers
    Singleton(const Singleton&) = delete; // no copies
    Singleton& operator=(const Singleton&) = delete; // no self-assignments
    Singleton(Singleton&&) = delete; // WHY?
    Singleton& operator=(Singleton&&) = delete; // WHY?
public:
    static T& getInstance() // singleton
    {
        static T instance; // Guaranteed to be destroyed.
                       // Instantiated on first use.
                       // Thread safe in C++11
        return instance;
    }
};
Run Code Online (Sandbox Code Playgroud)

然后我通过奇怪的重复模板模式(CRTP)使用

class Foo: public Singleton<Foo> // now Foo is a Singleton
{
    friend class Singleton<Foo>;
    ~Foo(){}
    Foo(){};
public:
// rest of the code
};
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚为什么我应该删除移动构造函数和赋值运算符.你能给我一个例子,如果我不删除(根本没有定义)移动ctor和赋值运算符,我最终会破坏单例吗?

Ker*_* SB 33

如果声明了一个复制构造函数(即使delete在声明中将其定义为d),也不会隐式声明移动构造函数.参看 C++ 11 12.8/9:

如果类的定义X没有显式声明一个移动构造函数,那么当且仅当一个类的定义被隐式声明为默认值时

- X没有用户声明的复制构造函数,

- ......

由于您确实拥有用户声明的复制构造函数,因此如果您没有声明复制构造函数,则根本不会有移动构造函数.所以你可以完全摆脱移动构造函数声明定义.移动赋值运算符也是如此.

  • +1我的意见与你的答案一致,但更强:作为一种风格指南,我建议不要删除移动成员**.他们的删除最多是多余的.在最坏的情况下,他们的删除是一个错误(虽然不是这种情况).因此,在代码审查中,如果我看到已删除的移动成员,则会强制我检查以确保我们不在bug区域中. (9认同)
  • 哦,我不知道,非常感谢链接,我不想为此付出代价:) (4认同)
  • @vsoftco:有时理解事情如何运作的最简单方法是阅读规则......它们可能有点令人生畏,但我强烈推荐它:-) (2认同)
  • 是的,我尝试过,但是没有标准,也没有找到关于何时没有隐式声明移动ctor的确切规则.例如http://en.cppreference.com/w/cpp/language/move_constructor我没有意识到当你"删除"一个副本时,你实际上是"声明"它:) (2认同)
  • @vsoftco:是的,是的,你必须要特别注意语言.用户提供的,用户声明的,用户定义的,隐式定义的,隐式声明的...您可以获得标准的当前工作草案[来自GitHub](https://github.com/cplusplus/draft) . (2认同)