Итак, я читал о Правило нуля.
Упрощенная версия: Я не понимаю цель этого правила. Правило трех и пяти является своего рода «правилом большого пальца», но я не вижу «практического правила» или каких-либо других конкретных намерений с этим правилом.
Подробная версия:
Позвольте мне процитировать:
Классы, которые имеют собственные деструкторы, конструкторы копирования / перемещения или
операторы копирования / перемещения должны иметь дело исключительно с правами собственности.
Другие классы не должны иметь пользовательских деструкторов, копировать / перемещать
конструкторы или операторы копирования / перемещения.
Что это значит? Что они подразумевают под владение, владение чем?
Они также показали пример кода (я думаю, это связано с введением):
class rule_of_zero
{
std::string cppstring;
public:
rule_of_zero(const std::string& arg) : cppstring(arg) {}
};
Что они хотят показать с этим, я действительно потерян на этом.
Кроме того, они также говорят о сценарии, когда вы имеете дело с полиморфным классом, когда деструктор объявляется общедоступным и виртуальным, и о том, что этот блок неявно перемещается. Таким образом, вы должны объявить их все по умолчанию:
class base_of_five_defaults
{
public:
base_of_five_defaults(const base_of_five_defaults&) = default;
base_of_five_defaults(base_of_five_defaults&&) = default;
base_of_five_defaults& operator=(const base_of_five_defaults&) = default;
base_of_five_defaults& operator=(base_of_five_defaults&&) = default;
virtual ~base_of_five_defaults() = default;
};
Означает ли это, что всякий раз, когда у вас есть базовый класс с деструктором, который объявлен как открытый, так и виртуальный, вы действительно должны объявить все другие специальные функции-члены по умолчанию? Если это так, я не понимаю, почему.
Я знаю, что это много путаницы в одном месте.
Правило нуля
Нулевое правило — еще одно практическое правило о том, как писать классы, которые должны использовать некоторые ресурсы, такие как память или другие объекты. В этом примере динамически выделяемая память, содержащая символы строки, является ресурсом, которым нужно управлять.
Рекомендуется позволить специализированным классам управлять ресурсами и делать только это. В этом примере std :: string заботится обо всех деталях управления выделенной памятью.
Правило появилось после введения C ++ 11, потому что язык и стандартная библиотека улучшились, предоставляя гораздо лучшие возможности для управления динамически распределенными временами жизни объектов (unique_ptr и shared_ptr). Также контейнеры теперь позволяют создавать на месте, устраняя еще одну причину динамического размещения. Вероятно, это следует рассматривать как обновление гораздо более старого правила трех.
Так что если вы ранее использовали бы новый в вашем конструкторе, чтобы создать некоторый член и удалять в деструкторе теперь вы должны использовать unique_ptr для управления временем жизни члена, получая конструкцию перемещения и назначение перемещения «бесплатно».
Общие указатели могут помнить правильный деструктор для вызова, поэтому общая потребность в виртуальном деструкторе исчезает для объектов, которые управляются исключительно через общий указатель, даже если они используются полиморфно.
Поэтому в основном класс, который может полагаться на своих членов для выполнения всех необходимых действий для инициализации, перемещения, копирования и уничтожения, не должен объявлять какие-либо специальные функции-члены.
Правило пяти
Как всегда, в C ++ все не так просто.
Как отметил Скотт Мейерс, если вам по какой-либо причине придется добавлять деструктор, неявная генерация конструкторов перемещения и оператора присваивания перемещения отключается, даже если компилятор может их сгенерировать.
Тогда компилятор с радостью скопирует ваш класс повсюду, вместо того, чтобы перемещать его, что может не соответствовать вашим ожиданиям. Это может, например, замедлить вашу программу, так как нужно больше копировать. Компилятор не будет предупреждать об этом по умолчанию.
Поэтому он рекомендует явно указать, какой из пяти специальных методов вы хотите, чтобы избежать неожиданностей из-за несвязанных изменений. Он по-прежнему рекомендует писать классы, не связанные с управлением ресурсами, чтобы можно было использовать значения по умолчанию, сгенерированные компилятором.
Других решений пока нет …