V832. It's better to use '= default;' syntax instead of empty body.
Если в классе специальные функции объявляются с '= default', класс остается тривиально копируемым. Это потенциально поможет копировать и инициализировать такой класс более оптимально.
Правила формирования специальных функций сложные. Поэтому при написании классов/структур лучшим решением будет определить явно некоторые из них для лучшего понимания кода. Вот примеры таких специальных функций: конструктор по умолчанию, конструктор копирования, оператор копирования, деструктор, конструктор перемещения, оператор перемещения.
struct MyClass
{
int x;
int y;
MyClass() {}
~MyClass() {}
};
или так:
// header
struct MyClass
{
int x;
int y;
};
// cpp-file
MyClass::MyClass() {}
MyClass::~MyClass() {}
Такие функции (конструктор по умолчанию и деструктор в примере) программист определяет с пустым телом. Однако при таком подходе класс может стать нетривиально копируемым, из-за чего компилятор не всегда сможет сгенерировать более оптимальный код. Поэтому C++11 вводит синтаксис '= default' для специальных функций:
struct MyClass
{
int x;
int y;
MyClass() = default;
~MyClass() = default;
};
Помимо того, что компилятор сам сгенерирует тела специальных функций, он сможет вывести спецификаторы 'constexpr' и 'noexcept' для них автоматически.
Стоит отметить, что при переносе определения специальных функций из тела класса компилятор считает их определенными пользователем. Это может привести к пессимизации, поэтому '= default' лучше по возможности добавлять непосредственно в теле класса.
Срабатывание не выдается, если:
- используемый стандарт ниже C++11;
- у конструктора есть список инициализации;
- класс не содержит нестатических полей.
Примечание про идиому PIMPL
Определения больших классов внутри заголовочного файла могут многократно увеличивать время компиляции проекта. Чтобы его сократить, можно вынести реализацию класса в отдельный компилируемый файл, а в заголовочном файле оставить только объявления методов и указатель на реализацию класса. Такой подход носит название PIMPL. Вот пример такого класса:
#include <memory>
// header
class MyClass
{
class impl;
std::unique_ptr<impl> pimpl;
public:
void DoSomething();
~MyClass();
};
// cpp-file
class MyClass::impl
{
public:
impl()
{
// does nothing
}
~impl()
{
// does nothing
}
void DoSomething()
{
// ....
}
};
void MyClass::DoSomething()
{
pimpl->DoSomething();
}
MyClass::~MyClass() {}
Добавление '= default' к деструктору в теле класса приведет к ошибкам компиляции, т.к. деструктор класса 'MyClass::impl' на данном этапе неизвестен (деструктор нужен для 'std::unique_ptr'). Поэтому при таком подходе реализация специальных функций переносится в компилируемый файл.
При переносе определения специальных функций из тела класса их пустые тела также можно заменить на '= default'. Это не даст прироста производительности, однако сделает код чище и проще для восприятия:
MyClass::~MyClass() = default;