Consider the case of class which does not have a destructor and constructor explicitly declared by the developer. I understand that a destructor for a class will be implicitly declared in this case. Then is it true that the destructor is implicitly defined, only when an object of the class is about to be destroyed?
Is the behavior of constructor also the same as above. Is it implicitly defined only when an object of the class is created?
EDIT
class A {
public:
};
int main() {
}
In the above code, ~A() will be implicitly declared. My question is whether it true that the definition for the destructor will be made implicitly, only if an object of the class is instantiated like
class A {
public:
};
int main() {
A a;
}
Or is it implicitly defined, even if object instantiation is not done ?
Yes, implicitly declared default constructors and destructors are implicitly defined when they are used to create or destroy instances of the object. In the words of the standard (C++11):
12.1/6: A default constructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used
(3.2) to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration.
12.4/5: A destructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used (3.2) to
destroy an object of its class type (3.7) or when it is explicitly defaulted after its first declaration.
So they are defined in your second code snippet, which creates and destroys an object of type A, but not in the first, which doesn't.
On the one hand, it is often impossible to decide whether an object is ever created/destroyed in any non-trivial program*, on the other hand, it doesn't really matter as long as the observable behavior remains the same.
However, there is a thin line between defined when object created/destroyed, and defined if needed. In my example below, Foo::Foo() needs to be defined, because there is the potential for it to be needed. However, you ask whether it is defined when the object is created, and the latter is not decidable.
*:
class Foo {};
int main(int argc, char *argv[]) {
if (argc>1) Foo(); // <- impossible to decide if ever constructed/destroyed
}
// On the other hand, compiler might be smart enough to observe that
// Foo does not have any visible behaviour, remove Foo entirely, and in
// effect spit out this:
int main() {}
Whether a function is defined is not something that is determined at runtime, so the destructor cannot be "defined, only when an object [..] is about to be destroyed" simply because your executable is static and not created for a specific run.
However, if no calls to your destructor exist in the final executable, the linker might chose to will remove the function altogether.
For the last point, consider this example:
class A {
A() {}
~A() {}
};
class B {
A a; // cannot access dtor nor ctor of A
};
If you never ever instantiate B this will actually compile and link because no B::B() and no B::~B() ever is synthesised. However, if you try to create an object of B the compiler will call you some colourful names, simply because you forced it to synthesise B::B() and B::~B() which it cannot do.
Related
EDIT: Added a field to the example class to make it non-trivially-destructible, and a clarification that it was not meant to be the point of the question.
Consider a simple class with no user-declared destructor, e.g.
struct A {
std::string s;
};
Note that the actual field doesn't matter - it's only here to make the classes non-trivially-destructible, so that it doesn't distract. In other words, imagine it's a "normal" everyday class, not exceptional in any way.
In this case, the compiler is going to generate the destructor for us. The overall question is: when exactly is this destructor generated and where is its body placed?
To be more specific:
does the compiler actually generate any source code? and if so, where is this source code placed?
if no actual source code is generated, and we move directly to some internal represention / machine code, the questions are the same - when is the generation triggered, and where is its representation stored?
The practical motivation for this question is the issue of using unique_ptr with incomplete types, as in std::unique_ptr with an incomplete type won't compile or related questions. The solution is to prevent the compiler from generating the destructor on its own, and to precisely control the location by ourselves, so that the generation happens only after the complete type definition has been seen. And while most answers mention that it's generated "too early", I couldn't find any specifics on when exactly does it happen.
I'd speculate that the destructor (and other auto-generated members) would be placed at the end of class definition, right before the closing brace, but it's just a guess.
Any normative references would be much appreciated as well.
Please also note that this question is not about the contents of the destructor - it's not about what it does, it's about where it's located.
tl;dr
Implicitly declared destructors are declared public inline and at the end of the class definition, e.g.:
struct A {
std::string s;
public: inline ~A(); // implicit destructor
};
Destructors only get defined when they're used in the current translation unit.
The Destructor Body will be able to use all types that were accessible at the class definition and additionally all types that were accessible at the point were the class was first used.
How the compiler generates the code for the destructor and where it'll ultimately end up with is not easily answerable, since it depends on the compiler, compilation flags and even the code that gets compiled.
Long Explanation
What the C++ Standard says
11.4.7 Destructors
If a class has no user-declared prospective destructor, a prospective destructor is implicitly declared as
defaulted (9.5). An implicitly-declared prospective destructor is an inline public member of its class.
11.4.4 Special member functions
Default constructors (11.4.5.2), copy constructors, move constructors (11.4.5.3), copy assignment operators,
move assignment operators (11.4.6), and prospective destructors (11.4.7) are special member functions.
An implicitly-declared special member function is declared at the closing } of the class-specifier. Programs
shall not define implicitly-declared special member functions.
So if you don't add a destructor to your class you'll get an implicit one that will be an inline public member of the class and declared at the the end of the class definition.
Note that it is only declared - not defined - so the compiler will not check if the destructor would compile at this point.
i.e. in your example it could look like this:
struct A {
std::string s;
// it's only *declared*, not defined
inline ~A();
};
The compiler only needs to define the destructor if it is used somewhere.
So unless you use A somewhere it's implicit destructor will never be defined and you won't get any errors.
So the following is valid c++ even though the destructor of Foo would not be able to be compiled because Miau is never defined:
struct Miau;
class Foo {
public:
std::unique_ptr<Miau> miauPtr;
};
// Miau never defined
// Foo never used
The actual point where the compiler needs to define the destructor is:
11.4.7 Destructors
A destructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used (6.3) or
when it is explicitly defaulted after its first declaration.
So the compiler needs to generate a definition for the destructor when you actually use it or when you explicitly default it (e.g. A::~A() = default;, which in your case doesn't apply)
At this point you would actually get an error if your implicit destructor doesn't compile (e.g. because one of the members uses an incomplete type)
The declarations that will be visible to the implicitly defined destructor are defined as follows:
10.6 Instantiation context
During the implicit definition of a defaulted function (11.4.4, 11.11.1), the instantiation context is the union
of the instantiation context from the definition of the class and the instantiation context of the program
construct that resulted in the implicit definition of the defaulted function.
So everything that was accessible at the point of the class definition and additionally everything that is accessible from the point where you first used the class is visible to the destructor.
e.g.:
#include <memory>
#include <string>
struct Miau;
struct Foo {
std::unique_ptr<Miau> miauPtr;
};
struct Miau { std::string s; };
void useFoo() {
Foo f; // first usage of Foo
// this forces the compiler to define the destructor for Foo.
// it'll compile without any error because at this point Miau
// is already defined.
}
godbolt example
Note that this is only the case for implicitly defined destructors.
If you explicitly define the destructor (even if you default it), then instead of the point of first use the point where you explicitly defined it will be used instead.
e.g. if you replace Foo from the example above with:
// ok - implicit declaration and implicit definition
struct Foo {
std::unique_ptr<Miau> miauPtr;
};
// ok - explicit declaration and implicit definition
struct Foo {
~Foo() = default;
std::unique_ptr<Miau> miauPtr;
};
// error - explicit declaration and explicit definition
struct Foo {
~Foo();
std::unique_ptr<Miau> miauPtr;
};
Foo::~Foo() = default; // if Miau is not defined before this line we'll get an error
godbolt example
What's up to the compilers
The standard only defines how the destructor will be declared in the class body and when it needs to be defined.
Everything else is the decision of the compiler - how he generates the code for the destructor (be it source code, some internal representation or directly bytecode) or where the code then gets stored.
So you might up with no code at all for the destructor when it gets inlined everywhere.
Or you might get one version of the destructor for each translation unit.
Or a single version of the destructor that gets called by all the translation units.
This might also depend on the compilation flags you use and even on the code itself - so without a concrete example there is no clear answer to what the compiler will do with the implicit destructor.
The only guarantee you have is that the code of the destructor will get executed when an A is destroyed, apart from that everything is in the hands of the compiler.
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 have some legacy code and I need to add a new class for the message (which is irrelevant to my question). But it turns out that I need to declare an empty constructor in order for some static to be initialized. Not a default constructor or compiler-provided, but empty user-defined. I tried to reduce the code to MWE and here what I get:
#include <iostream>
using namespace std;
struct Test
{
Test() {cout << "Test::Test()" << "\n";}
void dummy(){}
};
template<typename T>
struct Message
{
Message()
{
test.dummy(); // this call have to be here in order to initialize Test, but why?
}
static Test test;
};
template<typename T>
Test Message<T>::test;
struct A : public Message<A>
{
//A(){} // uncomment this (and comment the default one) to call the Test constructor
A() = default;
};
int main()
{
}
This is what happening:
The program itself is empty, i.e. no instances are created.
There's a CRTP for an A class, which seems to be critical to the example.
There's a static declaration for the base of A and I'm expecting it's constructor to be called.
There's a dummy call to the function that does nothing, but also critical.
The problem is that if I don't provide a custom constructor then the static constructor never gets called. And I can't understand why do I need this? What's the difference with defaulted or compiler generated? And why do I need to call a dummy function?
I believe there's a rule for that. I checked it with different versions of gcc and clang - the behavior is the same. I very appreciate links to the standard/documentation.
If you leave A constructor defaulted and never call it then there is no need to generate it and therefore no need to create test. If you explicitly default it at definition, call A constructor or access A::test it will be initialized properly.
12.1 Constructors [class.ctor]
7
A default constructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used (3.2) to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration.
struct A : public Message<A>
{
A() = default; // no constructor is emitted unless A is instantiated
A(); // declaration
};
A::A() = default; // explicit default definition
int
main()
{
A a; // instantiation
A::test; // just explicitly access test so it is initialized regardless of A constructor
}
C++14 [temp.inst]/2:
Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
This says clearly that Message<A>::test will not be initialized unless it is used in a way that requires its definition to exist.
The only expression in your program that would require the definition is test.dummy() in the constructor of Message<A> ; so if that expression is removed then test must not be initialized.
For the case where test.dummy() is present, note that it is inside a template function, the constructor of Message<A>. If this constructor is never instantiated, then test.dummy() will not be considered.
As pointed out by VTT, [class.ctor] says that the explicitly-defaulted constructor for A means that no constructor is defined unless an A is odr-used.
Your code doesn't odr-use an A, therefore A's constructor is not defined, therefore there is no invocation of base class constructor (which would only happen if if A's constructor was defined), therefore the constructor template Message<A>() is not instantiated, therefore test is not required to exist.
I have some legacy code and I need to add a new class for the message (which is irrelevant to my question). But it turns out that I need to declare an empty constructor in order for some static to be initialized. Not a default constructor or compiler-provided, but empty user-defined. I tried to reduce the code to MWE and here what I get:
#include <iostream>
using namespace std;
struct Test
{
Test() {cout << "Test::Test()" << "\n";}
void dummy(){}
};
template<typename T>
struct Message
{
Message()
{
test.dummy(); // this call have to be here in order to initialize Test, but why?
}
static Test test;
};
template<typename T>
Test Message<T>::test;
struct A : public Message<A>
{
//A(){} // uncomment this (and comment the default one) to call the Test constructor
A() = default;
};
int main()
{
}
This is what happening:
The program itself is empty, i.e. no instances are created.
There's a CRTP for an A class, which seems to be critical to the example.
There's a static declaration for the base of A and I'm expecting it's constructor to be called.
There's a dummy call to the function that does nothing, but also critical.
The problem is that if I don't provide a custom constructor then the static constructor never gets called. And I can't understand why do I need this? What's the difference with defaulted or compiler generated? And why do I need to call a dummy function?
I believe there's a rule for that. I checked it with different versions of gcc and clang - the behavior is the same. I very appreciate links to the standard/documentation.
If you leave A constructor defaulted and never call it then there is no need to generate it and therefore no need to create test. If you explicitly default it at definition, call A constructor or access A::test it will be initialized properly.
12.1 Constructors [class.ctor]
7
A default constructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used (3.2) to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration.
struct A : public Message<A>
{
A() = default; // no constructor is emitted unless A is instantiated
A(); // declaration
};
A::A() = default; // explicit default definition
int
main()
{
A a; // instantiation
A::test; // just explicitly access test so it is initialized regardless of A constructor
}
C++14 [temp.inst]/2:
Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
This says clearly that Message<A>::test will not be initialized unless it is used in a way that requires its definition to exist.
The only expression in your program that would require the definition is test.dummy() in the constructor of Message<A> ; so if that expression is removed then test must not be initialized.
For the case where test.dummy() is present, note that it is inside a template function, the constructor of Message<A>. If this constructor is never instantiated, then test.dummy() will not be considered.
As pointed out by VTT, [class.ctor] says that the explicitly-defaulted constructor for A means that no constructor is defined unless an A is odr-used.
Your code doesn't odr-use an A, therefore A's constructor is not defined, therefore there is no invocation of base class constructor (which would only happen if if A's constructor was defined), therefore the constructor template Message<A>() is not instantiated, therefore test is not required to exist.
Consider the following text:
[C++11: 12.4/11]: Destructors are invoked implicitly
for constructed objects with static storage duration (3.7.1) at program termination (3.6.3),
for constructed objects with thread storage duration (3.7.2) at thread exit,
for constructed objects with automatic storage duration (3.7.3) when the block in which an object is created exits (6.7),
for constructed temporary objects when the lifetime of a temporary object ends (12.2),
for constructed objects allocated by a new-expression (5.3.4), through use of a delete-expression (5.3.5),
in several situations due to the handling of exceptions (15.3).
A program is ill-formed if an object of class type or array thereof is declared and the destructor for the class is not accessible at the point of the declaration. Destructors can also be invoked explicitly.
Then why does this program compile successfully?
#include <iostream>
struct A
{
A(){ };
~A() = delete;
};
A* a = new A;
int main() {}
// g++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Is GCC just being permissive?
I'm inclined to say so, since it rejects the following yet the standard appears to have no particular rule specific to deleted destructors in an inheritance hierarchy (the only loosely relevant wording is pertinent to the generation of defaulted default constructors):
#include <iostream>
struct A
{
A() {};
~A() = delete;
};
struct B : A {};
B *b = new B; // error: use of deleted function
int main() {}
The first part is not ill-formed because the standard text doesn't apply - no object of type A is declared there.
For the second part, let's review how object construction works. The standard says (15.2/2) that if any part of construction throws, all fully constructed subobjects up to that point are destroyed in reverse order of construction.
This means that the code underlying a constructor, if all written out by hand, would look something like this:
// Given:
struct C : A, B {
D d;
C() : A(), B(), d() { /* more code */ }
};
// This is the expanded constructor:
C() {
A();
try {
B();
try {
d.D();
try {
/* more code */
} catch(...) { d.~D(); throw; }
} catch(...) { ~B(); throw; }
} catch(...) { ~A(); throw; }
}
For your simpler class, the expanded code for the default constructor (whose definition is required by the new expression) would look like this:
B::B() {
A();
try {
// nothing to do here
} catch(...) {
~A(); // error: ~A() is deleted.
throw;
}
}
Making this work for cases where no exception can possibly be thrown after initialization for some subobject has been completed is just too complex to specify. Therefore, this doesn't actually happen, because the default constructor for B is implicitly defined as deleted in the first place, due to the last bullet point in N3797 12.1/4:
A defaulted default constructor for class X is defined as deleted if:
[...]
any direct or virtual base class or non-static data member has a type with a destructor that is deleted or inaccessible from the defaulted default constructor.
The equivalent language exists for copy/move constructors as the fourth bullet in 12.8/11.
There is also an important paragraph in 12.6.2/10:
In a non-delegating constructor, the destructor for each direct or virtual base class and for each non-static data member of class type is potentially invoked.
It's that B's destructor is generated by the compiler at the line of your error and it has a call to A's destructor which is deleted, hence the error. In the first example nothing is trying to call A's destructor hence no error.
My guess is that this is what happens.
The implicitly generated B() constructor will first of all construct its base class subobject of type A. The language then states that if an exception is thrown during execution of the body of the B() constructor, the A subobject must be destroyed. Hence the need to access the deleted ~A() - it is formally needed for when the constructor throws. Of course, since the generated body of B() is empty this can never ever happen, but the requirement that ~A() should be accessible is still there.
Of course, this is 1) just a guess from my side of why there is an error in the first place and 2) not in any way a quote of the standardese to say whether this would actually be formally ill-formed or just an implementation detail in gcc. Could perhaps give you a clue of where in the standard to look though...
Accessibility is orthogonal to deletedness:
[C++11: 11.2/1]: If a class is declared to be a base class (Clause 10) for another class using the public access specifier, the public members of the base class are accessible as public members of the derived class and protected members of the base class are accessible as protected members of the derived class. If a class is declared to be a base class for another class using the protected access specifier, the public and protected members of the base class are accessible as protected members of the derived class. If a class is declared to be a base class for another class using the private access specifier, the public and protected members of the base class are accessible as private members of the derived class.
There is this:
[C++11: 8.4.3/2]: A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. [ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not potentially-evaluated. If a function is overloaded, it is referenced only if the function is selected by overload resolution. —end note ]
But you never "refer to" the deleted destructor.
(I still can't explain why the inheritance example doesn't compile.)