28

I have the following Singleton policy-class implementation:

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;
    }
};

which I then use via the curiously recurring template pattern (CRTP)

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

I cannot figure out why I should delete the move constructor and assignment operator. Can you give me a single example where I end up breaking the singleton if I don't delete (don't define at all) the move ctor and assignment operator?

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • 4
    Where did you read that you should? – Lightness Races in Orbit May 20 '14 at 22:46
  • 1
    No reason, you don't have to do that. – Kerrek SB May 20 '14 at 22:46
  • 1
    @LightnessRacesinOrbit here for example: http://stackoverflow.com/a/15187331/3093378 and I remember seeing it in some other code examples, although I cannot recall. I wondered why, because I thought that if I delete the copy ctor, then no move ctor will be defined implicitly – vsoftco May 20 '14 at 22:53
  • What's your use case for assignment/moving actually, otherwise of asking for a language definition for this case? – πάντα ῥεῖ May 20 '14 at 22:55
  • @πάνταῥεῖ I tried to see if I really need to declare it as deleted (i.e., if not, was it possible to break the singleton pattern by somehow moving e.g. in a vector the object returned by the `getInstance()`, i.e. invalidating the instance.) – vsoftco May 20 '14 at 23:04
  • @vsoftco And what's your use case saying that you need a singleton at all BTW? Are you asking for an XY problem? – πάντα ῥεῖ May 20 '14 at 23:04
  • @vsoftco: Yeah, you thought right. Those examples are silly. – Lightness Races in Orbit May 20 '14 at 23:07
  • May be all of [**these Q&A**](http://stackoverflow.com/search?q=%5Bc%2B%2B%5D+singleton+user%3A1413395) are actually related ... – πάντα ῥεῖ May 20 '14 at 23:12
  • @πάνταῥεῖ I really need a singleton. I am implementing a library in which I need to have a whole set of predefined templated `Eigen` matrices, before the `main()`. There is no way of initializing them in the header, so I need a global class in which the initialization is done in the constructor. These are global resources for my library. – vsoftco May 20 '14 at 23:14
  • @vsoftco _'I really need a singleton'_ That's certainly OK, if you are sure. I've often used singletons, though really tried to have them **once** per system. The next step is to define what _system_ is, and why it needs a single unique instance of something (kind of _'main applicatoin'_ may be). – πάντα ῥεῖ May 20 '14 at 23:22
  • Thanks everyone for the answers! – vsoftco May 20 '14 at 23:40

1 Answers1

50

If you declare a copy constructor (even if you define it as deleted in the declaration), no move constructor will be declared implicitly. Cf. C++11 12.8/9:

If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if

— X does not have a user-declared copy constructor,

— ...

Since you do have a user-declared copy constructor, there won't be a move constructor at all if you don't declare one. So you can just get rid of the move constructor declaration-definition entirely. Same for the move-assignment operator.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Ok, thanks for pointing out the standard! That's what I thought, I was never able to "trick" the compiler into moving my object. – vsoftco May 20 '14 at 22:54
  • 3
    @vsoftco: Sometimes the easiest way to understand how things work is to read the rules... they may be a little daunting, but I highly recommend it :-) – Kerrek SB May 20 '14 at 22:56
  • 2
    Yes, I tried, but don't have standard and didn't find the exact rule about when the move ctor is not declared implicitly. For example here http://en.cppreference.com/w/cpp/language/move_constructor I didn't realize that when you `delete` a copy ctor you are actually "declare" it :) – vsoftco May 20 '14 at 23:02
  • 2
    @vsoftco: Yes, yes, you have to pay careful attention to the language. User-provided, user-declared, user-defined, implicitly-defined, implicitly-declared... you can get the current working draft paper of the standard [from GitHub](https://github.com/cplusplus/draft). – Kerrek SB May 20 '14 at 23:05
  • 4
    Ohh I didn't know, thank a lot for the link, I didn't want to pay for it :) – vsoftco May 20 '14 at 23:11
  • @vsoftco: Right. As they say, "You can't own the standard." (because nobody can afford it). But you can own countless copies of the working draft, in all its stages. Some stages are tagged as "releases", e.g. the one after publication of C++11... – Kerrek SB May 20 '14 at 23:14
  • 13
    +1 My opinion is in agreement with your answer but even stronger: As a style guide, I recommend that the move members **never** be deleted. At best their deletion is redundant. At worst, their deletion is a bug (not in this case though). So in code reviews, if I see deleted move members, that forces me to check to make sure we are not in bug territory. – Howard Hinnant May 20 '14 at 23:25
  • @HowardHinnant, what do you mean exactly by "deleted move members"? – Vassilis Dec 19 '18 at 12:44
  • @Vassilis: I use the term "move members" to refer to the move constructor and move assignment operator. If they are "deleted", that means that they are defined using `= delete`. Here is more in-depth rationale for my position on this matter: https://stackoverflow.com/a/38820178/576911 – Howard Hinnant Dec 19 '18 at 14:01