In general, to completely prevent client code instantiation of a class you can declare the class final
and either
make the constructors non-public
, or
delete the constructors and make sure that the class isn't an aggregate, or
add a pure virtual member function (e.g. make the destructor pure virtual) to make the class abstract.
Declaring the class final
is necessary when the non-public
is protected
, and for the abstract class, in order to prevent instantiation of a base class sub-object of a derived class.
To partially prohibit instantiation, you can
- make the destructor non-
public
.
This prevents automatic and static variables, but it does not prevent dynamic allocation with new
.
- make the class' allocation function (the
operator new
) non-public
.
This prevents dynamic allocation via an ordinary new
-expression in client code, but it does not provide automatic and static variables, or sub-objects of other objects, and it does not prevent dynamic allocation via a ::new
-expression, which uses the global allocation function.
There are also other relevant techniques, such as an allocation function with extra arguments that make new
-expressions inordinately complicated and impractical. I used that once to force the use of a special macro to dynamically allocate objects, e.g. for a shared-from-this class. But that was in the time before C++11 support for forwarding of arguments; nowadays an ordinary function can do the job, and such a function can be made a friend
of the class.
The fact that the code compiles with at least one version of the clang compiler with -std=gnu++1z
, is due to a bug and/or language extension in that compiler.
The code should not compile, since it invokes the default constructor that has been deleted. And it does not compile with e.g. MinGW g++ 5.1.0, even with -std=gnu++1z
.
The fact that the code compiles with at least one version of the clang compiler with -std=gnu++1z
, may be due to a bug and/or language extension in that compiler. What the correct behavior is, is unclear because
Although the code compiles with clang and with Visual C++ 2015, it does not compile with e.g. MinGW g++ 5.1.0, even with -std=gnu++1z
.
Intuitively the delete
would be meaningless if the code should compile, but many meaningless constructs are permitted in C++.
At issue is whether the class is an aggregate (in which case the new
expression performs aggregate initialization), which rests on whether the deleted default constructor can be regarded as user-provided. And as user TartanLlama explains in comments, the requirements for user-provided are
C++11 §8.4.2/4
” A special member function is user-provided if it is user-declared and not explicitly
defaulted or deleted on its first declaration.
I.e. although the delete
of the default constructor in this question's example declares that constructor, it's not user-provided (and ditto for the other members) and so the class is an aggregate.
The only defect report I can find about this wording is DR 1355, which however just concerns an issue with the use of the words “special member”, and proposes to drop those words. But, considering both the effect demonstrated by this question, and considering that a function can only be deleted on its first declaration, the wording is strange.
Summing up, formally, as of C++11 (I haven't checked C++14), the code should compile. But this may be a defect in the standard, with the wording not reflecting the intent. And since MinGW g++ 5.1.0 doesn't compile the code, as of October 2015 it's not a good idea to rely on the code compiling.
operator new
andoperator delete
. typeA
is an aggregate, so the value initialization becomes aggregate initialization, which doesn't call a default (deleted) constructor – Biquadraticx
andy
accepted however (which I don't see why) – Overmeasurex
andy
are static in this code, not "stack" (which they would be if inside a function) – Overmeasure