Дефолтные конструкторы. Такие разные
#опытным
Существует 3 вида дефолтных конструкторов и важно понимать, в чем у них различия, чтобы разрешать нужную функциональность.
1️⃣
Тривиальный дефолтный конструктор
По сути задача дефолтного конструктора - вызывать у своих полей и подклассов дефолтный конструктор. А что если все поля класса имеют тривиальные типы?
struct Foo {
int i;
double d;
char c;
};
На самом деле
у всех тривиальных базовых типов в С++ есть конструктор по-умолчанию. Но он
тривиальный. То есть ничего вообще не делает и никак не инициализирует объект.
И это свойство может передастся конструктору Foo. Если для такого типа дефолтный конструктор будет сгенерирован компилятором, то он тоже ничего делать не будет.
Конструктор по-умолчанию называется тривиальным, если:
👉🏿 У класса нет виртуальных методов.
👉🏿 Все базы класса имеют тривиальные конструкторы по-умолчанию.
👉🏿 Все поля класса имеют тривиальные конструкторы по-умолчанию.
Все типы, которые совместимы с С, обладают этим свойством. Если вам нужна такая совместимость, тривиальный конструктор по-умолчанию - это ваш бро.
2️⃣
Нетривиальный дефолтный конструктор, сгенерированный компилятором
Если ваш класс содержит поле, у которого есть нетривиальный конструктор, то вам скорее всего и не нужна С-совместимость. Но вы можете приобрести кое-что другое.
Предоставив компилятору честь сгенерировать конструктор, вы разрешаете инициализировать объект с помощью агрегатной инициализации:
struct Foo {
// Foo() = default; так тоже можно
int i;
std::string s;
std::vector<int> v;
};
Foo f = {42, "Hello World", {1, 2, 3}};
можете даже
designated initialization воспользоваться:
Foo f = {.i = 42, .s = "Hello World", .v = {1, 2, 3}};
Там есть конечно
еще несколько требований, но опустим их, чтобы не сбивать фокус.
3️⃣
Нетривиальный пользовательский конструктор по-умолчанию
Как только вы сами определили дефолтный конструктор, то вы сразу же попали в эту категорию. И лишились преимуществ, описанных выше. Даже если вы определили пустой конструктор, он все равно считается кастомным:
struct Foo {
Foo() {};
int i;
std::string s;
std::vector<int> v;
};
Foo f = {42, "Hello World", {1, 2, 3}}; // ERROR
Да, с инициализацией у С++ довольно сложные отношения, но много чего идет от наследия С и обратной совместимости.
Don't be trivial. Stay cool.
#cppcore
Обсуждение 11
Обсуждение не доступно в веб-версии. Чтобы написать комментарий, перейдите в приложение Telegram.
Обсудить в Telegram