Does "= default" allow out-of-line implementations? - c++

Usually I see the = default syntax used in the header. My understanding is that this is the same as if the functions are explicitly implemented in the header, see Foo below.
Foo.h
#pragma once
class Foo
{
public:
Foo() = default;
Foo(const Foo& other) = default;
};
Purely out of curiosity, can the = default be used in the source files as follows?
Bar.h
#pragma once
class Bar
{
public:
Bar();
Bar(const Bar& other);
};
Bar.cpp
#include "Bar.h"
Bar::Bar() = default;
Bar::Bar(const Bar&) = default;
As far as I know this is equivalent to explicitly implementing the functions in the cpp file.
The above Bar example compiles with gcc-5.1 but does the standard allow for this usage?
As an aside, are there any benefits to using = default in the source file versus the header?

Yes this is legal. From [dcl.fct.def.default]
Explicitly-defaulted functions and implicitly-declared functions are collectively called defaulted functions, and the implementation shall provide implicit definitions for them (12.1 12.4, 12.8), which might mean defining them as deleted. A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration. A user-provided explicitly-defaulted function (i.e., explicitly defaulted after its first declaration) is defined at the point where it is explicitly defaulted; if such a function is implicitly defined as deleted, the program is ill-formed.
Emphasis mine
And then they go on to detail you exact scenario with
struct nontrivial1 {
nontrivial1();
};
nontrivial1::nontrivial1() = default; // not first declaration
So as long as the function is not implicitly marked as deleted then the function will be defined where you explicitly default it.
As an aside, are there any benefits to using = default in the source file versus the header?
The only "advantage" I can see it it allows existing code bases to change their cpp files to use modern techniques without having to change the header file. There is even a note in the standard:
Note: Declaring a function as defaulted after its first declaration can provide efficient execution and concise definition while enabling a stable binary interface to an evolving code base.

One potential usage of defaulting in the source file instead of the header is to use the pimpl idiom with unique_ptr. It requires a complete type for construction and destruction, so you can't define those special members in the header. You'd have to do:
Foo.h
struct Foo {
struct Impl;
unique_ptr<Impl> p;
Foo();
~Foo();
};
Foo.cpp
// Foo::Impl definition here
// now Impl isn't incomplete
Foo::Foo() = default;
Foo::~Foo() = default;

Yes, special member functions may be defaulted "out of line"; the compiler will generate the correct code and it will work as expected.
In fact, there is a rule relating to special members not being defaulted on first declaration, they are then considered user provided (and hence non-trivial).
A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration. A user-provided explicitly-defaulted function (i.e., explicitly defaulted after its first declaration) is defined at the point where it is explicitly defaulted; if such a function is implicitly defined as deleted, the program is ill-formed.
Link here [dcl.fct.def.default]. With the following example detailing your situation;
struct nontrivial1 {
nontrivial1();
};
nontrivial1::nontrivial1() = default; // not first declaration
Its usefulness lies in what it does, it provides the default implementation, but not at the point of declaration, thus making it user-provided. As noted, this is useful when dealing with an as-yet incomplete type, such as when using the pimpl idiom. It could also be used to mark your type as non-trivial, thus prohibiting its use in code that requires a trivial type (e.g. std::is_trivial).

There is a small change in the behaviour. Other TU than Bar.cpp can't see that they are defaulted because they only see the header. So putting default in the cpp will make your class not trivially assignable and not trivially constructible.
There are some case that you want to do this: if your class hold a unique_ptr to an incomplete type, it's a good practice to default the destructor in the cpp, because if you don't, classes that uses yours will be required the incomplete type's destructor to be visible.

When implementing in source file,
the methods are no longer defaulted but user provided.

Related

Practical difference between implicit and defaulted constructor in C++

As far as I know, in C++ default constructors are declared (and defined if needed) implicitly if there is no user-defined default constructors. However, a user can declare a default constructor explicitly with the default keyword. In this post the answers are mainly about the difference between the implicit and default terms, but I didn't see an explanation about whether there is some difference between declaring a constructor as default and not declaring it at all.
As an example:
class Entity_default {
int x;
public:
Entity_default() = default;
}
class Entity_implicit {
int x;
}
In the example above, I declare a constructor for Entity_default as default and let the compiler declare a default constructor implicitly for Entity_implicit. I assume I do call these constructors later on. Is there any difference between these constructors in practice?
To the best of my knowledge, there is no functional or theoretical difference, both are still "trivial."
Uses of an explicit default constructors:
To ensure it exists when it would not otherwise be created, i.e. if a different constructor exists
You can default it in a different compilation unit:
Header file:
struct Foo
{
std::string bar;
Foo() noexcept;
~Foo();
};
Source file:
Foo::Foo() noexcept = default;
Foo::~Foo() = default;
Useful if you don't want an inline constructor to save code size or ensure ABI compatibility. Note that at this point, it is no longer a trivial object.

Location of compiler-generated class methods

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.

Why do we need default generated destructor

For what situations we need to have a default generated destructor? It's pretty clear why we would need default generated constructors and operator=, but can't think of situation when default generated destructor should be used.
class A
{
...
~A() = default;
...
};
In cases where you'd like to hide the implementation of a class inside an inner class and keep a unique_ptr to an instance of that inner class (the pimpl idiom) you need to move the default destructor definition out of the class definition since unique_ptr can't work with incomplete types.
Example:
A.hpp (the header a user of the class will include)
#pragma once
#include <memory>
class A {
public:
A();
~A();
void foo() const;
private:
struct A_impl; // just forward declared
std::unique_ptr<A_impl> pimpl;
};
A_impl.hpp ("hidden" - not to be included in normal usage of A)
#pragma once
#include "A.hpp"
struct A::A_impl {
void foo() const;
};
A.cpp
#include "A_impl.hpp"
A::A() : pimpl(std::make_unique<A_impl>()) {}
A::~A() = default; // <- moved to after A_impl is fully defined
void A::foo() const { pimpl->foo(); }
A_impl.cpp
#include "A_impl.hpp"
#include <iostream>
void A::A_impl::foo() const { std::cout << "foo\n"; }
Demo
If you let the compiler generate A::~A() it will not compile. My compiler says:
unique_ptr.h:79:16: error: invalid application of ‘sizeof’ to incomplete type ‘A::A_impl’
static_assert(sizeof(_Tp)>0,
^~~~~~~~~~~
Demo
This seems to be asking when you would define the destructor for a class if the body of that destructor would be the same as the one the compiler generates.
Reasons include:
Clarity. If you have a class with copy/move constructors or copy/move assignment operators, it is typically managing some resource. Many coding guidelines would require you define the destructor to show that it wasn't just overlooked, even it is equivalent to the compiler-generated one.
Some aspect of the function differs from the one the compiler would generate. If you want a virtual destructor, you have to define it. Similarly, a throwing destructor must be defined.
You want to control the place the destructor is generated. You can define a destructor outside of the class definition. You might need to do this for cyclically dependent classes as in one of the other answers. You may want to do this to define a stable ABI. You may want to do this to control code generation.
In all these cases, you must or want to define the destructor, even though the body is nothing special. Why would you use = default versus an empty body? Because the compiler-generated destructor is equivalent to the one you get with = default, and you only want to change the aspects of the destructor you are trying to change. An empty body is not the same as = default in C++, because a defaulted function can be defined as deleted. An empty body also rules out trivial destructibility, even if that was otherwise an option.
C++ Core Guidelines C.21: If you define or =delete any copy, move, or destructor function, define or =delete them all
Reason
The semantics of copy, move, and destruction are closely related, so if one needs to be declared, the odds are that others need consideration too.
Declaring any copy/move/destructor function, even as =default or =delete, will suppress the implicit declaration of a move constructor and move assignment operator. Declaring a move constructor or move assignment operator, even as =default or =delete, will cause an implicitly generated copy constructor or implicitly generated copy assignment operator to be defined as deleted. So as soon as any of these are declared, the others should all be declared to avoid unwanted effects like turning all potential moves into more expensive copies, or making a class move-only.
Note
If you want a default implementation (while defining another), write =default to show you're doing so intentionally for that function. If you don't want a generated default function, suppress it with =delete.
So this mainly depends on what is declared in the class.
Generally it is about The rule of three/five/zero
If the class needs a custom copy/move function, but nothing special for a destructor, then =default should be used on the destructor.

Linker error for different declarations of default constructors

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()'

What are the rules for noexcept on default defined move constructors?

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).