C++ требует очень внимательного отношения к владению ресурсами. Особенно это касается динамически созданных объектов. Особенно в ситуациях, когда могут порождаться исключения (а какой же современный C++ без использования исключений ;)). Вот простой пример ошибки, может возникнуть, когда забываешь про exception safety.
Есть объект, который хранит в себе указатели на динамически созданные объекты. Эти указатели ему передаются посредством метода add. Логика метода add проста: он сохраняет переданный указатель у себя, а уничтожит все полученные таким образом объекты в своем деструкторе. Поскольку логика метода add проста, то и реализация кажется простой:
class some_object_holder_t { std::vector< A * > m_objects; public : ... void add( std::unique_ptr< A > object ) { m_objects.push_back( object.release() ); } } |
Но я вижу в этом простом коде одну проблему: если при работе push_back произойдет исключение (например, не хватит памяти для расширения вектора), то переданный в add() объект не будет уничтожен. Почему? Да потому, что он уже не будет находиться под контролем std::unique_ptr, ведь метод unique_ptr::release() отработает еще до входа в push_back.
Вот и получаем неприятную ошибку на ровном месте. Неприятную потому, что она может очень долго не проявляться (пока при каком-то стечении обстоятельств push_back не бросит исключение). Поэтому написавший такой код разработчик может сам никогда и не столкнуться с ее последствиями.
Если бы метод add был написан вот так:
void add( std::unique_ptr< A > object ) { m_objects.push_back( object.get() ); object.release(); } |
То не было бы нарушения exception safety и, как следствие, очень неприятной и редко возникающей ошибки.
Комментариев нет:
Отправить комментарий