Понравилась заметка на habrahabr по декларативному программированию в С++: https://habrahabr.ru/post/270545/. (загляните в конец аннотации).
1) В статье говорится, что использовать напрямую try-catch - не очень хорошая идея, т.к. код будет нечитабельным (об этом же можно узнать почитав другие статьи по теме RAII-классов).
2) в статье описывается решение (уже лежит в boost 10 лет, но сейчас об этом говорят на конференциях по С++ достаточно много). Схематично показано как это решение внутри устроено - это особенно понравилось.
3) Дополнение (содержит мое личное мнение и с автором статьи не связано). Что касается примера из статьи - я бы (хотя кто я такой?) заменил его на что-то типа
int *a = new int[25];
int *b = new int[25];
Проблема примера точно такая же как и в примере из статьи (но такой код гигабайтами пишут студенты и поэтому им будет понятно о чем речь) - оператор new может выкинуть исключение. Если bad_alloc вылетит при первом new - то утечки не будет, а при втором - будет.
Решение проблемы очевидно - использовать RAII классы, например вектор. Если объект создается на стеке и если будет выработано исключение - стек "разматывается" и для таких объектов вызываются деструкторы.
vector<int> a;
vector<int> b;
Тут утечки не будет. В стандартной библиотеке С++ есть куча готовых классов, поддерживающих идиому RAII - fstream сам закроет файл, unique_ptr (и все прочие умные указатели) сам освободит память при выходе из функции (в т.ч. по исключению) и т.п. Очевидно, что RAII работает прекрасно и про это можно прочитать:
- Идиома RAII. Объекты управления ресурсами в C++: https://pro-prof.com/forums/topic/resources-control-objects-raii
- Умный указатель unique_ptr: https://pro-prof.com/forums/topic/cplusplus-unique_ptr-smart_pointers
4) Ну а что же делать, если при возникновении исключения надо выполнять какие-то нестандартные действия? (Еще одна проблема) - не городить же каждый раз RAII-класс? На самом деле, пример когда это нужно привести не так просто, в примере из статьи проблема могла бы быть решена использованием std::string (тоже RAII класс). Но допустим, такая ситуация возникает.
В качестве решения Александреску предложил идиому Scope Guard. Boost реализует ее и предлагает использовать макросы типа SCOPE_FAIL, которые создают на стеке анонимную переменную, для которой будет вызван деструктор при возникновении исключения. Ну и к этой переменной привязывают лямбду, которая и будет вызвана в деструкторе. Решение в бусте чуть сложнее, т.к. деструктор проверяет причины возникновения исключения (наша лямбда вызывается не во всех случаях).
Некоторые детали реализации можно найти в статье.
![]()
Это интересно
0
|
|||
Последние откомментированные темы: