Синтаксис конструктора C++ по умолчанию [дубликат]


На этот вопрос уже есть ответ здесь:

У меня есть вопрос о конструкторе по умолчанию в C++. Например, в классе A, в чем разница между использованием этого конструктора по умолчанию A(){}; или A() = default; ? А в чем вообще разница между ними? они?

Заранее благодарю вас!

3 3

3 ответа:

Конструктор, определенный как defaulted в первом объявлении, считается не предоставленным пользователем. Это по сути похоже на то, что подразумевается в C++03. Такое объявление конструктора допускается в классе aggregate.

struct ag {
    ag() = default;

    int a;
    double b;
};

struct nag {
    nag() {}

    int a;
    double b;
};

ag a = { 5, 12. }; // OK
nag na = { 5, 12. }; // error: not an aggregate and no appropriate constructor

Это правило применяется только тогда, когда = default появляется внутри класса. Дано следующее определение класса:

struct nag {
    nag();

    int a;
    double b;
}; 

Тогда эти определения конструктора действительно были бы полностью эквивалентны:

nag::nag() {} // 1
nag::nag() = default; // 2

Конструктор по умолчанию explicit обычно отключает пустой синтаксис инициализации списка копий (= {}) и {} в качестве аргумента или значения return. Конструктор по умолчанию с явным дефолтом и explicit в aggregate не подпадает под это правило, поскольку инициализация aggregate имеет более высокий приоритет, чем инициализация конструктора. Это дает возможность определить, является ли класс агрегатом, но вы, вероятно, не должны этого делать.

struct sadistic {
    explicit sadistic() = default;

    // members
};

sadistic se = {}; // OK only if sadistic has no virtual functions, etc.

Поведение конструкторов по умолчанию одинаково для A() {} и A() = default; в 12. 1p6:

Неявно определенный конструктор по умолчанию выполняет набор инициализаций класса, который был бы выполнен написанным пользователем конструктором по умолчанию для этого класса без ctor-инициализатора (12.6.2) и пустого compound-оператора.

Различия заключаются в следующем:

  • является ли конструктор constexpr (явно-дефолтный конструктор является constexpr, Если это будет быть действительным),
  • является ли класс агрегатом (8.5. 1p1), и
  • приводит ли инициализация значения к вызову конструктора по умолчанию, если явно заданный конструктор по умолчанию тривиален (8. 5p7).

Для последнего пункта:

#include <iostream>

struct A { int i; A() = default; };
struct B { int j; B() {} };

int main() {
    int i = 42, j = 42;
    new (&i) A();
    new (&j) B();
    std::cout << i << std::endl;  // 0
    std::cout << j << std::endl;  // 42
}

Таким образом, Вы можете написать пользовательский конструктор по умолчанию без дефолта, если, например, ваш класс имеет тривиальные члены, которые было бы дорого инициализировать нулем (например, большой массив), но это очень нишевый случай.

Различий не так уж много:

Старый синтаксис (обратите внимание, что ; не требуется):

A() {}

Доступен с первых дней C++. Он будет по умолчанию строить каждый базовый класс и переменную-член.

Новый синтаксис C++11:

A() = default;

Делает то же самое, но явно указывает на то, что это значение по умолчанию, поэтому вам (или компилятору) не нужно проверять, действительно ли фигурные скобки пусты.

Обратите внимание, что если класс не имеет объявленных конструкторов, компилятор добавлю один для вас.

исправление : существует разница, если конструктор по умолчанию удаляется, то есть неявный конструктор по умолчанию класса недопустим. В этом случае {} является синтаксической ошибкой, а =default - как удаленное определение:

struct S
{
    int &r;  //non default constructible

    S() {} //error: uninitialized reference S::r;
    S() = default; //ok: deleted constructor
    S() = delete;  //also ok (but not both!)
};