Чтение онлайн

на главную - закладки

Жанры

Стандарты программирования на С++. 101 правило и рекомендация

Александреску Андрей

Шрифт:
Ссылки

[Cargill92] pp. 77-79, 207 • [Cline99] §21.06, 21.12-13 • [Henricson97] pp. 110-114 • [Koenig97] Chapters 4,11 • [Meyers97] §14 • [Stroustrup00] §12.4.2 • [Sutter02] §27 • [Sutter04] § 18

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).

2

Nefarious — нечестивый, гнусный (англ.). — Прим. перев.

• Трудно безопасно использовать классы с членами или базовыми классами

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

52. Копируйте и ликвидируйте согласованно

Поделиться:
Популярные книги

Долгий путь домой

Русич Антон
Вселенная EVE Online
Фантастика:
космическая фантастика
попаданцы
6.20
рейтинг книги
Долгий путь домой

Убивать чтобы жить 6

Бор Жорж
6. УЧЖ
Фантастика:
боевая фантастика
космическая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 6

Возвышение Меркурия. Книга 3

Кронос Александр
3. Меркурий
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 3

Фиктивная жена

Шагаева Наталья
1. Братья Вертинские
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Фиктивная жена

Здравствуй, 1985-й

Иванов Дмитрий
2. Девяностые
Фантастика:
альтернативная история
5.25
рейтинг книги
Здравствуй, 1985-й

Барон Дубов 4

Карелин Сергей Витальевич
4. Его Дубейшество
Фантастика:
юмористическое фэнтези
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Барон Дубов 4

Лекарь для захватчика

Романова Елена
Фантастика:
попаданцы
историческое фэнтези
фэнтези
5.00
рейтинг книги
Лекарь для захватчика

Идеальный мир для Лекаря 24

Сапфир Олег
24. Лекарь
Фантастика:
городское фэнтези
попаданцы
5.00
рейтинг книги
Идеальный мир для Лекаря 24

Ваше Сиятельство 9

Моури Эрли
9. Ваше Сиятельство
Фантастика:
боевая фантастика
попаданцы
стимпанк
аниме
фэнтези
5.00
рейтинг книги
Ваше Сиятельство 9

Господин следователь

Шалашов Евгений Васильевич
1. Господин следователь
Детективы:
исторические детективы
5.00
рейтинг книги
Господин следователь

Академия проклятий. Книги 1 - 7

Звездная Елена
Академия Проклятий
Фантастика:
фэнтези
8.98
рейтинг книги
Академия проклятий. Книги 1 - 7

Полковник Гуров. Компиляция (сборник)

Макеев Алексей Викторович
Полковник Гуров
Детективы:
криминальные детективы
шпионские детективы
полицейские детективы
боевики
крутой детектив
5.00
рейтинг книги
Полковник Гуров. Компиляция (сборник)

Первый среди равных. Книга V

Бор Жорж
5. Первый среди Равных
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Первый среди равных. Книга V

Землянка для двух нагов

Софи Ирен
Фантастика:
космическая фантастика
5.00
рейтинг книги
Землянка для двух нагов