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.
Related
I have been playing around with default constructors and noticed a weird behavior (from my point of view).
When I declare A() = default, I get no linker error.
struct A
{
int a;
A() = default;
};
A a; // no linker error
However, when I declare A(); I get it.
struct A
{
int a;
A();
};
A a; // linker error - undefined reference to `A::A()`
Questions:
What's the difference between the two?
And if A(); produces a linker error, why is it supported in the first place? Any practical applications?
UPDATE (Follow-up Question)
For A(); why can't it be implicitly defined by the compiler if no definition is specified by the user?
In the first case the compiler itself defines the constructor.
Take into account that in the first case the constructor declaration is at the same its definition.
In the second case as the constructor is a user-defined constructor then it is the user who must to define the constructor. In the second case there is only a declaration of the constructor.
Take into account that you can declare a constructor and then define it using the specifier default.
For example
#include <iostream>
struct A
{
int a;
A();
};
A::A() = default;
int main()
{
A a;
return 0;
}
The purpose of writing
A();
is to declare to the compiler that a definition of what A() should actually do will be given somewhere else (by you!), and if it is given in another compilation unit (cpp-file) the linker is responsible for finding this definition.
A() = default;
is a way of declaring to the compiler that it should create a definition of what should be done on construction of an A, automatically, subject to the rules of the language. So because the definition is already given, the linker won't complain about not finding it.
Why is it supported to declare without defining A() in the first place? Because you want to be able to compile different cpp-files independently. Otherwise you would always have to compile all your code, even if 99% of it hasn't changed.
The construction of an A will most likely be defined in "A.cpp". If you have completed the design of your struct A then ideally "A.cpp" will be compiled once and never again. If you construct an A in a different class/struct/compilation unit "B.cpp" then the compiler can trust in the existence of a definition for A() while compiling "B.cpp", without knowing what the definition actually looks like.
As to the follow-up question, "why it can't be defined implicitly": this is probably a misunderstanding about why errors occur. Compiler/linker errors do not occur to punish you. They don't mean that the compiler is pretending not to be able to do something although it can. Errors occur in order to remind you that you are breaking your own promises and any attempt by the compiler or the linker to repair that, might be possible, but is most likely not going to work as you want it to, because there are signs that you have lost track of your own requirements.
That being said, A() could be defined implicitely. But if you write "A();" you are explicitely telling the compiler not to do it implicitly, and telling the linker to remind you, if you should ever forget to define it. This doesn't only apply to constructors but to every kind of method, most of which have no natural sense of what it means to define them implicitely. What is the default definition of "A.makeMoney"? It is non-trivial and by writing A.makeMoney(); you are telling the compiler: "trust me, I'm gonna define somewhere how it's gonna be done".
(15.1 Constructors)
A default constructor for a class X is a constructor of class X for
which each parameter that is not a function parameter pack has a
default argument (including the case of a constructor with no
parameters). If there is no user-declared constructor for class X, a
non-explicit constructor having no parameters is implicitly declared
as defaulted (11.4). An implicitly-declared default constructor is an
inline public member of its class.
Purpose of
A() = default;
is to tell compiler to create default constructor, as if no constructor was defined by user. Consider this case
struct A
{
int a;
A(int v): a(v) {}
};
A a; // compiler error, no default constructor
If ANY constructor was declared by user, default one will be gone.
By adding A() = default; to that declaration you would allow class A to be constructed that way. It is explicitly-defaulted (11.4.2)
A function definition whose function-body is of the form = default ;
is called an explicitly-defaulted definition. A function that is
explicitly defaulted shall
(1.1) — be a special member function,
(1.2) — have the same declared function type (except for possibly
differing ref-qualifiers and except that in the case of a copy
constructor or copy assignment operator, the parameter type may be
“reference to non-const T”, where T is the name of the member
function’s class) as if it had been implicitly declared, and
(1.3) — not have default arguments.
Methods follow same linking rules as any functions with external linking. If you declare any method in class body and your code refers to that method (in case of constructor - by creating object of this class), you have to define it in any compilation module of same program, otherwise program will be ill-formed.
struct A
{
A() = default;
Here, you're saying that the constructor should be implemented automagically, i.e. any class members that have a default constructor will be initialized with it, and any class members that don't have a default constructor will be left uninitialized.
struct A
{
A();
Here, you're saying that you will implement a default constructor. So you have to implement it. E.g.
A::A()
: a(42)
{
}
This is additional information, and is supplemental to the answer provided by others.
There is a difference w.r.t. the context of special member functions, when we use the terms such as defaulted, undeclared and deleted.
When a special member function is:
undeclared : It does not participate in overload resolution. To use this functionality, just don't declare the special member function.
deleted : It participates in overload resolution. It prevents compilation, if used anywhere. To use this functionality, the keyword is delete
defaulted : It participates in overload resolution. The default, compiler generated code is provided as the definition. To use this functionality, the keyword is default
There is an interesting talk by Howard Hinnat on the same, where he explains when the special member functions are defaulted/deleted/undeclared - https://www.youtube.com/watch?v=vLinb2fgkHk
Adding more info for A::A();
Referring to class.ctor/1.2:
The class-name shall not be a typedef-name. In a constructor
declaration, each decl-specifier in the optional decl-specifier-seq
shall be friend, inline, explicit, or constexpr.
[ Example:
struct S {
S(); // declares the constructor
};
S::S() { } // defines the constructor
— end example ]
Thus, A(); is just a declaration and not a definition causing:
undefined reference to `A::A()'
I'm running a static analysis tool and getting an error because an abstract class, with no data members, has no constructors.
Given an abstract class with no data members:
class My_Interface
{
public:
virtual void interface_function(void) = 0;
};
Are any constructors generated by the compiler?
If a constructor is generated, what would it's content be?
If a constructor is generated, would it be eliminated by an
optimization level?
The rule documentation in the static analysis says:
If you do not write at least one constructor in a class, the compiler will
write a public constructor for you by default. This rule detects if you
do not declare at least one constructor.
The rule documentation references Scott Meyers, "Effective C++: 55 Specific Ways to Improve your Programs and Design", third edition.
My understanding is that the compiler will not generate constructors for the above case.
Edit 1:
This is not a duplicate of many constructor questions because:
This one has no data members.
This is not asking if a constructor is necessary, but what happens
when a constructor is not provided.
This is C++ language.
The compiler at least theoretically synthesizes a constructor even in this case. Even though you can't create an instance of this class, the constructor will be invoked in the process of creating a derived class (that overrides interface_function, so it can be instantiated).
Given that this is basically a pure interface class, the constructor probably won't do anything, so most compilers will probably optimize it out (quite possibly even when you don't tell it to optimize the code).
Are any constructors generated by the compiler?
Yes. Several. First, from [class.ctor]:
A default constructor for a class X is a constructor of class X that either has no parameters or else each
parameter that is not a function parameter pack has a default argument. If there is no user-declared constructor
for class X, a non-explicit constructor having no parameters is implicitly declared as defaulted (8.4).
An implicitly-declared default constructor is an inline public member of its class. A defaulted default
constructor for class X is defined as deleted if:
Several bullet points follow, none of which apply. So we have the equivalent of:
My_Interface() = default;
Then, from [class.copy]:
If the class definition does not explicitly declare a copy constructor, a non-explicit 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).
So we have:
My_Interface(const My_Interface&) = default;
Also:
If the definition of a class X does not explicitly declare a move constructor, a non-explicit one will be implicitly
declared as defaulted if and only if
(9.1) — X does not have a user-declared copy constructor,
(9.2) — X does not have a user-declared copy assignment operator,
(9.3) — X does not have a user-declared move assignment operator, and
(9.4) — X does not have a user-declared destructor.
So we also have:
My_Interface(My_Interface&& ) = default;
If a constructor is generated, what would it's content be?
All three are generated, all three are = default;
If a constructor is generated, would it be eliminated by an optimization level?
None of the three constructors are trivial because My_Interface has a virtual function. As such, at the very least, the vtable will need to be initialized/copied. So something will have to happen, even if there aren't any members to initialize/copy/move.
Q1. Are any constructors generated by the compiler?
Answer: Yes. From the C++11 Standard:
12.1 Constructors
5 A default constructor for a class X is a constructor of class X that can be called without an argument. If
there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared
as defaulted (8.4). An implicitly-declared default constructor is an inline public member of its class.
I don't see anything in the standard that answers the other two questions. However, in your case, since there is a virtual member function, the default constructor must, at least, set the virtual table of the object.
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.
struct Base{
Base(Base &){} // suppress default constructor
};
struct Derived : Base{
};
int main(){
Derived d;
}
The code shown gives error because the default constructor (implicit) of 'Base' is suppressed. Indeed the standard says in $12.1 "If there is no user-declared constructor for class X, a default constructor is implicitly declared."
There are three things:
a) Does the standard say anywhere that
if the user declared constructor is
present in a class, the default
constructor (implicit) is suppressed. It is bascically the above phrased negatively or is it once again implied :)?
b) Why is it that way?
c) Why the same rules do not apply for the default destructor?
I think that a) is sufficiently clearly implied by your quote.
As for “why” – quite simple: a default constructor is not always meaningful; if there were no way to suppress it, this would weaken C++ substantially.
As for c), a class without destructor (no “default”, just plain destructor) is simply not meaningful.
a) Does the standard say anywhere that
if the user declared constructor is
present in a class, the default
constructor (implicit) is suppressed.
It is bascically the above phrased
negatively or is it once again implied
:)?
Yes, that is the meaning
b) Why is it that way?
Most likely, if you have a user-defined constructor, it means special work needs to be done to initialize the object. It makes sense to disable the implicitly generated default constructor in such a case, because it likely won't do any of the special work.
c) Why the same rules do not apply for the default destructor?
Well, perhaps it would make sense for the language to enforce the "rule of three" (if you define one of copy constructor, assignment operator or destructor, chances are you need to implement all three), but it just doesn't.
Perhaps the rationale is that there are several ways to initialize a class, but assignment and destruction often works the same way (memberwise assignment, run destructor of all members).
The shortest answer is because you declared a constructor for the class Base, no default constructor is created (thus the suppression). You cannot initialize Derived because Derived has no default constructor to call on class Base. (this is because the default constructor of derived that is generated for you can only construct it's parent class with the default constructor)