51. Деструкторы, функции освобождения ресурсов и обмена не ошибаются
51. Деструкторы, функции освобождения ресурсов и обмена не ошибаются
Резюме
Все запуски этих функций должны быть успешными. Никогда не позволяйте ошибке выйти за пределы деструктора, функции освобождения ресурса (например, оператора delete) или функции обмена. В частности, типы, деструкторы которых могут генерировать исключения, категорически запрещено использовать со стандартной библиотекой С++.
Обсуждение
Перечисленные функции не должны генерировать исключений, так как они являются ключевыми для двух главных операций транзакционного программирования — отката при возникновении проблем в процессе работы и принятия результата работы, если проблем не возникло. Если нет способа безопасного возврата в предыдущее состояние при помощи операций, не генерирующих исключения, то невозможно реализовать бессбойный откат; отсутствие возможности безопасного сохранения изменения состояния при помощи операции, не генерирующей исключения, делает невозможной реализацию бессбойного принятия результата работы.
Рассмотрим следующие советы и требования, найденные в Стандарте С++.
Если деструктор, вызванный в процессе свертки стека, выходит с исключением, вызывается функция terminate (15.5.1). Поэтому деструкторы должны в общем случае перехватывать исключения и не позволять им распространиться за пределы деструктора.
— [C++03] §15.2(3)
В стандартной библиотеке C++ не определен ни один деструктор [включая деструкторы любого типа, используемого для инстанцирования шаблона стандартной библиотеки], генерирующий исключение.
— [C++03] §17.4.4.8(3)
Деструкторы являются специальными функциями, и компилятор автоматически вызывает их в различных контекстах. Если вы пишете класс — назовем его, к примеру, Nefarious[2] — деструктор которого может давать сбой (обычно посредством генерации исключения; см. рекомендацию 72), то вы столкнетесь с такими последствиями.
• Объекты Nefarious трудно безопасно использовать в обычных функциях. Вы не можете надежно инстанцировать автоматические объекты Nefarious в области видимости, если возможен выход из этой области видимости посредством исключения. Если это произойдет, деструктор Nefarious (вызываемый автоматически) может попытаться сгенерировать исключение, которое приведет к неожиданному завершению всей программы посредством вызова Терминатора — std::terminate (см. также рекомендацию 75).
• Трудно безопасно использовать классы с членами или базовыми классами Nefarious. Плохое поведение класса Nefarious распространяется на все классы, для которых он является базовым или у которых имеются члены этого типа.
• Вы не можете надежно создавать глобальные либо статические объекты Nefarious. Исключение, которое может быть сгенерировано их деструкторами, невозможно перехватить.
• Вы не можете надежно создавать массивы объектов Nefarious. Коротко говоря, массивы при наличии деструкторов, которые могут генерировать исключения, обладают неопределенным поведением, поскольку в этой ситуации просто невозможно придумать способ разумного отката. (Подумайте сами: какой именно код должен сгенерировать компилятор для создания массива из десяти объектов Nefarious, если у четвертого объекта в конструкторе происходит генерация исключения, а при откате, когда вызываются деструкторы уже сконструированных объектов, один или несколько деструкторов генерируют исключения? Удовлетворительного ответа в этой ситуации просто нет.)
• Вы не можете использовать объекты Nefarious в стандартных контейнерах. Объекты Nefarious нельзя хранить в стандартных контейнерах или использовать их с какими-то другими частями стандартной библиотеки. Стандартная библиотека запрещает использование деструкторов, которые могут генерировать исключения.
Функции освобождения ресурсов, включая специальным образом перегруженные операторы operator delete и operator delete[], попадают в ту же категорию, поскольку в общем случае они также используются в процессе "зачистки", в частности, в процессе обработки исключений.
Помимо деструкторов и функций освобождения ресурсов распространенные безопасные методики основаны на том, что операции обмена не генерируют исключений. В данном случае это связано не с использованием их в реализациях отката, а с их использованием в гарантированном принятии результатов работы. Например, вот идиоматическая реализация оператора operator= для некоторого типа T, который основан на выполнении копирующего конструктора, за которым следует вызов функции обмена, не генерирующей исключений:
T& T::operator=(const T& other) {
T temp(other);
Swap(temp);
}
(см. также рекомендацию 56)
К счастью, область видимости сбоя при освобождении ресурса имеет определенно меньший размер. Если для сообщения об ошибке используются исключения, убедитесь, что рассматриваемые функции обрабатывают все возможные исключения и прочие ошибки, которые могут возникнуть при работе функций. (В случае исключений просто оберните все, что делает ваш деструктор, в блок try/catch(...).) Это чрезвычайно важно, поскольку деструктор может быть вызван в кризисной ситуации, такой как сбой при выделении системного ресурса (например, памяти, файлов, блокировок, портов, окон или других системных объектов).
При использовании в качестве механизма обработки ошибок исключений следует документировать такое поведение, объявляя такие функции с закомментированной пустой спецификацией исключений /* throw() */ (см. рекомендацию 75).
Ссылки
[C++03] §15.2(3), §17.4.4.8(3) • [Meyers96] §11 • [Stroustrup00] §14.4.7, §E.2-4 • [Sutter00] §8, §16 • [Sutter02] §18-19
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Операции освобождения
Операции освобождения int sem_post(sem_t* sem);Эта операция увеличивает на единицу (инкремент) внутренний счетчик семафора, и в этом она диаметрально противоположна операции блокировки. Если перед этим значение счетчика семафора было равно 0, то один из потоков, ожидающих
Пример обмена сообщениями с помощью менеджера ресурсов
Пример обмена сообщениями с помощью менеджера ресурсов Код файла заголовков #define NET_OPER "/net/904-3"#define NET_REG "/net/Bed-Test"// Максимальная длина обычного стандартного сообщения.#define MESSIZE_MAX 100// Максимальная длина инвентаризационного имени процесса#define PROC_NAME_MAX 100struct IdLabel_t { // Структура,
2. Конструкторы и деструкторы
2. Конструкторы и деструкторы Конструкторы и деструкторы являются специализированными формами методов. Используемые в связи с расширенным синтаксисом стандартных процедур New и Dispose конструкторы и деструкторы обладают способностью размещения и удаления динамических
3. Деструкторы
3. Деструкторы Borland Pascal предоставляет специальный тип метода, называемый сборщиком мусора (или деструктором) для очистки и удаления динамически размещенного объекта. Деструктор объединяет шаг удаления объекта с какими-либо другими действиями или задачами, необходимыми
R.12.4 Деструкторы
R.12.4 Деструкторы Деструктором называется функция-член класса cl с именем ~cl, она используется для уничтожения значений типа cl непосредственно перед уничтожением объекта, содержащего их. Деструктор не имеет формальных параметров и для него нельзя задать тип возвращаемого
60. Избегайте выделения и освобождения памяти в разных модулях
60. Избегайте выделения и освобождения памяти в разных модулях РезюмеЗолотое правило программиста — положи, где взял. Выделение памяти в одном модуле, а освобождение в другом делает программу более хрупкой, создавая тонкую дальнюю зависимость между этими модулями. Такие
4.2.5. Значение освобождения
4.2.5. Значение освобождения В начале данной книги упоминалась ссылка на Дзэн об "особой передаче знаний вне священного писания". Не следует рассматривать ее как экзотическую, использованную ради стилистического эффекта. Основные понятия Unix всегда отличались свободной,
4.2.5. Значение освобождения
4.2.5. Значение освобождения В начале данной книги упоминалась ссылка на Дзэн об "особой передаче знаний вне священного писания". Не следует рассматривать ее как экзотическую, использованную ради стилистического эффекта. Основные понятия Unix всегда отличались свободной,
Формализованный шаблон освобождения ресурсов
Формализованный шаблон освобождения ресурсов Текущая реализация MyResourceWrapper работает вполне приемлемо, но некоторые недостатки она все же имеет. Во-первых, каждому из методов Finalize() и Dispose() приходится очищать одни и те же неуправляемые ресурсы. Это, конечно, ведет к
13.7. Получение ресурсов из библиотеки ресурсов
13.7. Получение ресурсов из библиотеки ресурсов Постановка задачи Требуется получить фотографии или видео непосредственно из библиотеки фотографий, не прибегая к использованию каких-либо встроенных компонентов графического пользовательского
8.5. Функции getrlimit() и setrlimit(): лимиты ресурсов
8.5. Функции getrlimit() и setrlimit(): лимиты ресурсов Функции getrlimit() и setrlimit() позволяют процессу определять и задавать лимиты использования системных ресурсов. Аналогичные действия выполняет команда ulimit, которая ограничивает доступ запускаемых пользователем программ к ресурсам.У
17.4.5. Деструкторы
17.4.5. Деструкторы Когда заканчивается время жизни объекта производного класса, автоматически вызываются деструкторы производного и базового классов (если они определены), а также деструкторы всех объектов-членов. Например, если имеется объект класса NameQuery:NameQuery nq( "hyperion"
17.5.8. Виртуальные функции, конструкторы и деструкторы
17.5.8. Виртуальные функции, конструкторы и деструкторы Как мы видели в разделе 17.4, для объекта производного класса сначала вызывается конструктор базового, а затем производного класса. Например, при таком определении объекта NameQueryNameQuery poet( "Orlen" );сначала будет вызван
8.5.7 Деструкторы
8.5.7 Деструкторы Функция член класса cl с именем ~cl называется деструтором. Деструктор не возвращает никакого значения и не полчает никаких параметров; он используется для уничтожения знчений типа cl непосредственно перед уничтожением содержащего их объекта. Деструктор не
Механизм освобождения
Механизм освобождения Другой важной процедурой класса MEMORY является dispose (не путайте с тезкой Pascal, которая освобождает память). Она связана с важной практической проблемой, иногда называемой финалом или окончательным завершением (finalization). Если сборщик мусора утилизирует
31. Деструкторы
31. Деструкторы Borland Pascal предоставляет специальный тип метода, называемый сборщиком мусора (или деструктором) для очистки и удаления динамически размещенного объекта. Деструктор объединяет шаг удаления объекта с какими-либо другими действиями или задачами, необходимыми