Legalize throwing destructors! D's scope(failure) and scope(success) in C++
От: Evgeny.Panasyuk Россия  
Дата: 27.09.12 19:02
Оценка: 194 (8)
stack_unwinding это маленькая header-only библиотека, которая реализует примитив(class unwinding_indicator) позволяющий определить, был ли вызван деструктор объекта из-за раскрутки стэка или "нормальным" образом

Библиотека позволяет определить в каких случаях реально опасно кидать исключение из деструктора. То есть когда исключение покинувшее деструктор может привести к вызову std::terminate.
В результате, возможно достичь такого же эффекта, как ручная расстановка ".close()" в конце блока, автоматически.
{
   File a,b;
   // ...
   b.close(); // may throw
   a.close(); // may throw
}

станет
{
   File a,b;
   // ...
}

В более общем случае, это поможет созданию "продвинутого" Scope Guard, который не требует ручного вызова commit/release, а также "понимает" исключения из деструкторов.
Язык D имеет scope(success) и scope(failure), которые позволяют задать отложенное действие на конец блока, которое выполняются(либо нет) в зависимости от того, произошёл ли выход из блока по исключению или обычным образом.

В этой библиотеке есть примеры реализаций "scope(success)" и "scope(failure)" (C++03, без лямбд):
{
    cout << "Case #1: stack unwinding" << endl;
    scope_action exit=make<scope_exit>(Print(" exit"));
    scope_action failure=make<scope_failure>(Print(" failure")); 
    scope_action success=make<scope_success>(Print(" success"));
    throw 1;
}


В Boost есть библиотека "Scope Exit", которая в примерах использует решение похожее на ручной вызов release/commit (там используется bool переменная).
Цитата из мануала Boost.ScopeExit:

Boost.ScopeExit is similar to scope(exit) feature built into the D programming language.

A curious reader may notice that the library does not implement scope(success) and scope(failure) of the D language.
Unfortunately, these are not possible in C++ because failure or success conditions cannot be determined by calling std::uncaught_exception (see Guru of the Week #47 for details about std::uncaught_exception and if it has any good use at all).
However, this is not a big problem because these two D's constructs can be expressed in terms of scope(exit) and a bool commit variable (similarly to some examples presented in the Tutorial section).


Работоспособность библиотеки была проверенна на: {MSVC2005,MSVC2008,MSVC2010,MSVC2012,GCC 4.1.2,Clang 3.2}x{x32,x64}x{дефолтные настройки}

На данный момент, библиотека реализована поверх платформо-зависимой реализации функции uncaught_exception_count.
uncaught_exception_count — это функция подобная std::uncaught_exception из стандартной библиотеки, но вместо булевского результата возвращает unsigned int, показывающий текущее количество uncaught exceptions

Ссылки:
* http://www.boost.org/doc/libs/1_51_0/libs/scope_exit/doc/html/index.html
* http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2012/Three-Unlikely-Successful-Features-of-D
* http://www.drdobbs.com/cpp/generic-change-the-way-you-write-excepti/184403758
* http://www.gotw.ca/gotw/047.htm
* https://github.com/panaseleus/stack_unwinding
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.