How can I prohibit the construction of an object? I mark = delete; all relevant special functions as follows:
struct A
{
A() = delete;
A(A const &) = delete;
A(A &&) = delete;
void * operator new(std::size_t) = delete;
void operator delete(void *) = delete;
};
A x{};
A y = {};
A * z = ::new A{};
LIVE EXAMPLE
But x, y and *z can still exist. What to do? I am interested in both cases; static/stack allocation and heap allocation.
One option would be to give the class a pure virtual function, and mark it final:
struct A final
{
virtual void nonconstructible() = 0;
};
[Live example]
If you want to have just static members, then write namespace A rather than struct A. Ensuing code will be syntactically similar.
To prevent creation of an instance of a class, make it abstract. (Include one pure virtual function). But doing this introduces a v-table into you class, which you might not want.
If you want to make it impossible to instantiate the class you could just declare private constructors:
class NotInstantiable {
private:
NotInstatiable();
public:
};
And not defining NotInstantiable further. This can't now be instantiated since first the constructor is private but also that a definition for the constructor has not been provided.
The second obstacle for instantiate the NotInstantiable would for example prohibit this possibility, which in fact otherwise is a well known pattern:
class NotInstantiable {
private:
NotInstantiable();
public:
NotInstantiable* evil_method()
{
return new NotInstantiable(); // this will fail if there's no body of the constructor.
}
};
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.
Essentially this compiles and is allowed because the type A is an aggregate type and the aggregate initialisation doesn't use default constructors.
What is an aggregate type?;
class type (typically, struct or union), that has
no private or protected members
no user-provided constructors (explicitly defaulted or deleted constructors are allowed) (since C++11)
no base classes
no virtual member functions
Giving it any one of the above would make it non-aggregate and thus the aggregate initialisation would not apply. Giving it a private user defined (and unimplemented) constructor will do.
struct A
{
A() = delete;
A(A const &) = delete;
A(A &&) = delete;
void * operator new(std::size_t) = delete;
void operator delete(void *) = delete;
private:
A(int);
};
As a side note; I hope this is a defect in the language specifications. At first look I thought that this should not compile, yet it does. One of the motivations for the =delete was to avoid the C++03 "trick" of declaring the constructors private to "hide" them and thus be unusable. I would expect a =delete on the default constructor to effectively prohibit class creation (outside other user defined constructors).
For easier reading and clearer intent, consider even an empty base class;
struct NonAggregate{};
struct A : private NonAggregate
{
//...
Maybe the simplest yet is to return to the C++03 style here, make the default constructor private;
struct A
{
private:
A(); // note no =delete...
};
Related
I can understand defaulted constructors, since user defined constructors will disable the compiler generated ones making the object non trivially copyable etc.
In the destructor case, apart from changing access category, what use is there to define a defaulted destructor considering that no user defined member function can disable them (you can't overload destructors anyway) ?
// Which version should I choose ?
struct Example
{
//1. ~Example() = default;
//2. ~Example() {}
//3.
};
Even in the case of virtual destructors, defaulting them would not make them trivial so what good is it doing it?
The exception for trivial destructors omission has to do with the derived class' destructor, not the base one. So virtual ~Foo() = default; is a useful construct to keep the default destructor, but virtualize it.
One use is making the destructor protected or private while potentially keeping the class trivial: just list it after the desired access specifier.
Another: when writing classes, some programmers like to order the class's functions: e.g. constructors, then the destructor, then the non-const "mutating" members, then the const "accessor" members, then static functions. By being able to explicitly = default the destructor, you can list it in the expected order and the reader looking there knows there can't be another misplaced version of it. In large classes, that may have some documentary/safety value.
It also gives you something concrete around which to add comments, which can help some documentation tools realise the comments relate to destruction.
Basically it is about communicating the intent, but pretty redundant.
But in case you're using std::unique_ptr as a member of class you'll need to declare destructor (but only declare) in header. Then you can make it use default implementation in source file like so:
MyClass:~MyClass() = default;
Considering your options I would use first or third one.
As mentioned by Nikos Athanasiou in a comment, a default constructor makes the type trivially destructible, where a user defined one does not. A little code sample will show it:
#include <iostream>
#include <type_traits>
struct A { ~A() = default; };
struct B { ~B() {} };
struct C { ~C() noexcept {} };
int main() {
std::cout
<< std::is_trivially_destructible<A>::value
<< std::is_trivially_destructible<B>::value
<< std::is_trivially_destructible<C>::value
<< std::endl;
return 0;
}
Displays
100
As for virtual destructors, consistency with non-virtual ones and Quentin's answer are appropriate reasons. My personal advice is that you should always use the default when you can, as this is a way to stick to the most canonic behavior.
In the following fragment of code I receive a compiler error when the method Data::setValue(int, int) is declared virtual:
struct Data{
int ma;
int mb;
virtual void setValues(int a, int b){
ma = a;
mb = b;
}
};
struct ThreadMessage {
enum type {
DATA
};
type msg_type;
union content {
Data d;
int a;
}content;
};
The error that the compiler (g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3) gives me is:
struct.cpp:19:14: error: member 'Data ThreadMessage::content::d' with
constructor not allowed in union
struct.cpp:19:14: error: member 'Data ThreadMessage::content::d' with copy assignment operator not allowed in union
This set of compiler errors took me completely off guard. In the actual code, I had many more attributes and functions. Therefore, I started looking where I put the bloody operator=() and constructor but I didn't write them in struct Data.
I know my problem disappears when I make the Data::setValues as not virtual. But why does the struct Data have a constructor? When exactly does a struct have a constructor in C++? And why does the compilation error disappear when I make virtual void Data::setValues(int, int) non virtual?
Barring the default access of members, a struct and a class are identical in C++.
Unless you program carefully (and have C++11), you cannot have a class or a struct member in a union since there would be ambiguity as to how such members of the union should be constructed.
That's what your compiler is telling you.
You may want to browse through this thread: Struct Constructor in C++?
The Reader's Digest version is that, like classes, structs have a default constructor, which you can overload and define however you like.
The error messages you quoted are misleading, so no doubt you wonder why making the function non-virtual fixes the problem.
First - structs and classes in C++ have constructors and copy assignment operators. If you do not create them yourself, they will be created for you. (You may delete those default versions). In your example there is an automatically generated constructor of Data, and also automatically generated assignment operator.
Now why the error messages are misleading? Because they are not true. In C++ you can have union members with constructors or assignment operators. The problem starts when those member functions are not trivial. Before C++11 it was just not possible to have an union member with non-trivial constructor. C++11 changed it, but still without writing additional functions it is not possible to use such union.
A struct/class with virtual functions has non-trivial member functions as constructor and assignment operator (because hidden data member needs to be managed). This is why when you make the function non-virtual the errors disappear - then the member functions become trivial and your struct may be used as a union member without problems.
When exactly does a struct have a constructor in c++
Always.
The error message is a bit confusing, but it's saying that you cannot have a class there.
A class is a type defined with either the struct keyword or the class keyword.
Every class has a constructor and an assignment operator, whether it's user-provided or not.
The compiler error message is a bit misleading. From the conceptual language point of view your class Data will have a constructor in any case, regardless of whether the function is virtual or not.
The compiler is apparently a pre-C++11 one (or works in pre-C++11 mode). And it does not like the fact that Data's constructor is non-trivial. It is specifically the non-triviality of Data's constructor that makes the compiler to say that Data is a class "with constructor".
In this particular case the constructor becomes non-trivial once you introduce at least one virtual function into the class.
A non-trivial constructor is a constructor that has to do something (in your case - initialize the per-object household information that support polymorphism). I.e. it is a constructor that must exist physically in generated code. Meanwhile a trivial constructor exists only conceptually, but produces no code. The compiler is referring to that physical distinction when it separates classes into ones "with constructor" and ones "without constructor".
Especially in connection with std::vector it is important that types are noexcept movable when possible.
So when declaring a move constructor = default like in
struct Object1
{
Object1(Object1 &&other) = default;
};
std::is_nothrow_move_constructible<Object1>::value will be true as every member (0 here) of Object1 is nothrow-move-constructible, which is answered here.
Yet what happens if the move copy constructor is only declared and then later = default defined like in the following code?
struct Object2
{
Object2(Object2 &&other);
};
Object2::Object2(Object2 &&other) = default;
With g++ 4.9.2 std::is_nothrow_move_constructible<Object2>::value is false and I have to mark both the declaration and the definition as noexcept to make it true.
Now what I am interested in is what the actual rules are.
Especially since Item 22 in Effective Modern C++ (Scott Meyers) seems to give ill advice by suggesting to implement the pimpl-idiom move constructor like I did with Object2.
[dcl.fct.def.default]/p2:
If a function is explicitly defaulted on its first declaration,
it is implicitly considered to be constexpr if the implicit declaration would be, and,
it has the same exception specification as if it had been implicitly declared (15.4).
These rules do not apply if the function is explicitly defaulted on a later declaration, as in your later example, so instead, except for destructors, the function is considered noexcept(false) by default like most other functions.
Since the explicit defaulting can be in a different translation unit - and in the pimpl case, is in a different TU - there's no general way for the compiler to figure out after seeing the class definition only whether the move constructor will throw, unless the function is explicitly defaulted in the class definition (i.e., at its first declaration).
In C++11, a polymorphic class (one with virtual member methods) should/must have a virtual destructor (so that delete on a base-class pointer does the expected). However, declaring an destructor explicitly deprecates the implicit generation of the copy constructor (though this may not be widely implemented by compilers) and hence also of the default constructor. Thus, for any polymorphic class to not be deprecated it must have these members
virtual ~polymorphic_class() = default;
polymorphic_class() = default;
polymorphic_class(polymorphic_class const&) = default;
explicitly defined, even if they are trivial. Am I correct? (Isn't this annoying?) What is the logic behind this? Is there any way to avoid that?
Am I correct?
Yes, as per ForEveR's post.
Is there any way to avoid that?
Yes. Do this just once by implementing a base for all polymorphic classes (similarly to class Object in Java and D which is the root of all class hierarchies):
struct polymorphic {
polymorphic() = default;
virtual ~polymorphic() = default;
polymorphic(const polymorphic&) = default;
polymorphic& operator =(const polymorphic&) = default;
// Those are not required but they don't harm and are nice for documentation
polymorphic(polymorphic&&) = default;
polymorphic& operator =(polymorphic&&) = default;
};
Then, any class publicly derived from polymorphic will have a implicitly declared and defined (as defaulted) virtual destructor unless you declare one yourself.
class my_polymorphic_class : public polymorphic {
};
static_assert(std::is_default_constructible<my_polymorphic_class>::value, "");
static_assert(std::is_copy_constructible <my_polymorphic_class>::value, "");
static_assert(std::is_copy_assignable <my_polymorphic_class>::value, "");
static_assert(std::is_move_constructible <my_polymorphic_class>::value, "");
static_assert(std::is_move_assignable <my_polymorphic_class>::value, "");
What is the logic behind this?
I can't be sure. What follows are just speculations.
In C++98/03, the Rule of Three says that if a class needs either the copy constructor, the copy assignment operator or the destructor to be user defined, then it probably needs the three to be user defined.
Obeying the Rule of Three is a good practice but this is nothing more than a guideline. The Standard doens't force it. Why not? My guess is that people realized this rule only after the publication of the Standard.
C++11 introduced move constructor and move assignment operator, turning the Rule of Three into the Rule of Five. With benefit of hindsight, the committee wanted to enforce the Rule of Five. The idea was: if either of the five special functions is user declared then the others, but the destructor, won't be implicitly defaulted.
However, the committee didn't want to break virtually every C++98/03 code by enforcing this rule and then, decided to do it only partially:
If either the move constructor or the move assignment operator is user declared then other special functions, but the destructor, will be deleted.
If either of the five special functions is user declared then the move constructor and move assignment operators won't be implicitly declared.
In the case of C++98/03 well formed code, neither a move constructor nor a move assignment operator is ever user declared then, rule 1 doesn't apply. Hence when compiled with a C++11 compliant compiler C++98/03 well formed code doesn't fail to compile as a consequence of this rule. (If it does, it's for some other reasons.)
In addition, under rule 2 the move constructor and move assignment operator are not implicitly declared. This doesn't break C++98/03 well formed code either because they never expected the declaration of move operations anyway.
The deprecation mentioned in the OP and quoted in ForEveR's post suggests a possible enforcement of the Rule of Five by a future Standard. Be prepared!
You are correct, that should be true by standard in future, but now it's only deprecated, so every compiler should support implicitly-declared copy constructor, when destructor is virtual now.
n3376 12.8/7
If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class
definition declares a move constructor or move assignment operator, the implicitly declared copy constructor
is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has
a user-declared copy assignment operator or a user-declared destructor.
And it seems to me, that you cannot make any workaround for this.
Today I stumbled over a code snippet like this one:
class A
{
A() = default;
A (const A&) = delete;
...
}
I've never seen either the delete or default keyword. Are they part of C++11 std? And what are they used for?
Special member functions can now be defaulted or deleted.
A deleted member function still takes part in overload resolution, but if it gets chosen, the program is ill-formed and compilation stops with a useful diagnostic. This is The Right Way to write things like non-copyable classes, and the user gets a proper error message.
A defaulted member function "does what it should", e.g. a defaulted default constructor default-initializes all bases and members and has empty body; a defaulted copy constructor copies each base and member object, and a defaulted assignment operator assigns each base and member object. If any of those operations aren't allowed (e.g. you have reference members), then the defaulted member function is defined as deleted.
Note that your first declaration-definition A() = default; makes the constructor A::A() user-declared but not user-defined; this is important for the classification of A, e.g. whether it is POD. (And notice that this is different from struct A { A(); }; A::A() = default; which is user-defined.)
Another nice consequence is the clarification of implicitly generated things: If you don't write certain functions yourself at all (like copy constructors), one gets implicitly declared for you. When the implicitly-declared one is odr-used, it gets implicitly defined as defaulted, and thus if it's not possible (e.g. if the class has non-copyable members), it actually gets implicitly defined as deleted. So that's generally a neat way of propagating things like non-copyability and non-assignability, at least in terms of the language and the consequent diagnostics.