Если целью является предотвращение создания экземпляров класса, вам необходимо убедиться, что вы не можете вызвать какой-либо конструктор. Если вы явно не запрещаете конструкцию копирования, то вы оставляете за компилятором решение решать, включать его или нет, в зависимости от условий, при которых удаляется неявно объявленным конструктором копирования , которые:
- T has non-static data members that cannot be copied (have deleted, inaccessible, or ambiguous copy constructors);
- T has direct or virtual base class that cannot be copied (has deleted, inaccessible, or ambiguous copy constructors);
- T has direct or virtual base class with a deleted or inaccessible destructor;
- T is a union-like class and has a variant member with non-trivial copy constructor;
- T has a data member of rvalue reference type;
- T has a user-defined move constructor or move assignment operator (this condition only causes the implicitly-declared, not the defaulted, copy constructor to be deleted).
Итак, если мы предположим, что у вас есть класс A, который пытается предотвратить конструирование самого себя, только запретив конструкцию по умолчанию и не добавляя ничего в списоквыше, можно использовать неявный конструктор копирования, чтобы получить экземпляр A или даже наследовать его. Например:
class A
{
A(){};
};
struct B : public A {
B() : A(*a)
{}
A* a;
};
B b;
A a (*static_cast<A*>(nullptr));
Теперь по общему признанию приведенный выше код может вызвать непредвиденное поведение, и любой приличный компилятор выдаст предупреждения, если вы попытаетесь это сделать, но он скомпилируется. Практичность такого подхода будет полностью зависеть от того, что еще было объявлено в A ...
. Я бы сказал, что если идея состоит в том, чтобы остановить творение, то вам нужно убедиться, что все методы построения предотвращены. Следовательно, гораздо лучше подходить к явному удалению конструктора: default, конструктора copy и конструктора move. Это посылает гораздо более четкое заявление о намерениях, и я считаю, что это должно предотвратить все методы построения.
class CantInstantiate
{
public:
CantInstantiate() = delete;
CantInstantiate(const CantInstantiate&) = delete;
CantInstantiate(CantInstantiate&&) = delete;
...
};