How does an empty default constructor differ from =default;?

For the default constructor,
how does an empty body differ from what is obtained with =default?

X::X() {}
// и
X::X() = default;
Author: Qwertiy, 2016-02-20

2 answers

Having a default constructor with an empty body automatically makes the class non-trivial. With all the features that follow from this. For example, makes the type not POD. It also eliminates the possibility of using aggregate initialization:

#include <iostream>
#include <type_traits>

struct X {
    //X() {}
    X() = default;      
    int a;
    int b;
};

int main( ) {
    X x { 1, 2 }; // ошибка, если X - не тривиальный класс.
    std::cout << std::boolalpha << 
        std::is_trivial<X>::value << "\n"; 
}

When defining a constructor as = default, the triviality of the class is preserved, if it was before that. In this case, this is equivalent to not having explicitly mention the constructor in defining the class.

If the default constructor is defined as = default outside of the class definition, it will still be considered that the constructor is provided by the user, and this also makes the class non-trivial.

A footnote to the Standard on this subject (8.4.2 / 5):

A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration.


The difference will also be observed when trying to create a constant object of the class by the default constructor. For example:

const X x;

Will result in compilation error when defining the X class as:

struct X {
    X() = default;
    int i;
};

And compiles successfully in the case of a user-provided default constructor:

struct X {
    X() {}
    int i;
};

Another point that demonstrates the difference occurs when using an empty initialization list when defining an object. For example:

X x = { };

Will result in resetting all class members with = default or an explicitly missing constructor. If the constructor is defined with an empty body, then such an entry will leave the class members uninitialized (garbage).

 22
Author: αλεχολυτ, 2018-02-19 05:38:37

The definition with =default;, as well as the absence of a definition (implicit definition), means that the compiler itself must choose the appropriate implementation.
In particular the compiler can define a remote function:

struct X {
  int& r;
  // X() {}       // ошибка, "r" не инициализрована
  X() = default;  // OK, компилятор сгенерирует X() = delete; (sic!)
                  // ссылка r не позволяет сгенерировать конструктор по умолчанию.
  X(int& r) : r(r) {}
};

This is not very useful in normal code, but it can be useful inside a template - depending on the types of class members, the compiler will choose whether to make a constructor or delete it.

 20
Author: Abyx, 2017-05-12 11:47:27