Для конструктора по умолчанию,
чем пустое тело отличается от того что получается с =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) {}
};
Это мало полезно в обычном коде, но может пригодиться внутри шаблона - в зависимост
от типов членов класса, компилятор сам выберет надо ли делать конструктор или удалить его.
Комментариев нет:
Отправить комментарий