Classes and class hierarchies
C.44
Предпочитайте конструкторам по умолчанию быть простыми и не выбрасывающими
Причина
Возможность установить значение на "значение по умолчанию" без операций, которые могут не работать, упрощает обработку ошибок и рассуждение о операциях перемещения.
Пример, проблемный
template<typename T>
// elem указывает на пространство-elem элемент, выделенный с помощью new
class Vector0 {
public:
Vector0() :Vector0{0} {}
Vector0(int n) :elem{new T[n]}, space{elem + n}, last{elem} {}
// ...
private:
own<T*> elem;
T* space;
T* last;
};
Это хорошо и общее, но установка Vector0 на пусто после ошибки включает выделение, которое может не работать. Также, наличие Vector0 по умолчанию как {new T[0], 0, 0} кажется расточительным. Например, Vector0<int> v[100] стоит 100 выделений.
Пример
template<typename T>
// elem это nullptr или elem указывает на пространство-elem элемент, выделенный с помощью new
class Vector1 {
public:
// устанавливает представление на {nullptr, nullptr, nullptr}; не выбрасывает
Vector1() noexcept {}
Vector1(int n) :elem{new T[n]}, space{elem + n}, last{elem} {}
// ...
private:
own<T*> elem {};
T* space {};
T* last {};
};
Использование {nullptr, nullptr, nullptr} делает Vector1{} дешевым, но особым случаем и подразумевает проверки во время выполнения. Установка Vector1 на пусто после обнаружения ошибки тривиальна.
Применение
- Отмечайте выбрасывающие конструкторы по умолчанию