Страницы

Поиск по вопросам

понедельник, 25 ноября 2019 г.

Чем пустой конструктор по умолчанию отличается от =default;?


Для конструктора по умолчанию,
чем пустое тело отличается от того что получается с =default?

X::X() {}
// и
X::X() = default;

    


Ответы

Ответ 1



Наличие конструктора по умолчанию с пустым телом автоматически делает класс нетривиальным Со всеми вытекающими отсюда особенностями. Например делает тип не POD. А также исключает возможность использовать агрегатную инициализацию: #include #include struct X { //X() {} X() = default; int a; int b; }; int main( ) { X x { 1, 2 }; // ошибка, если X - не тривиальный класс. std::cout << std::boolalpha << std::is_trivial::value << "\n"; } При определении конструктора как = default тривиальность класса сохраняется, есл она была до этого. В данном случае, это равносильно отсутствию явного упоминания конструктора в определении класса. Если конструктор по умолчанию определен как = default вне определения класса, вс равно будет считаться, что конструктор предоставлен пользователем, и это тоже делает класс нетривиальным. Сноска на Стандарт по этому поводу (8.4.2/5): A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration. Различие также будет наблюдаться при попытке создания константного объекта класса конструктором по умолчанию. Например: const X x; приведет к ошибке компиляции при определении класса X как: struct X { X() = default; int i; }; И скомпилируется удачно в случае предоставленного пользователем конструктора по умолчанию: struct X { X() {} int i; }; Еще один момент, демонстрирующий различие, возникает при использовании пустого списка инициализации при определении объекта. Например: X x = { }; приведёт к обнулению всех членов класса при = default или отсутствующем явно конструкторе Если же конструктор будет определён с пустым телом, то такая запись оставит члены класса неинициализированными (мусор).

Ответ 2



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

Комментариев нет:

Отправить комментарий