| |
| [/ Copyright (C) 2006-2009, 2012 Alexander Nasonov ] |
| [/ Copyright (C) 2012 Lorenzo Caminiti ] |
| [/ Distributed under the Boost Software License, Version 1.0 ] |
| [/ (see accompanying file LICENSE_1_0.txt or a copy at ] |
| [/ http://www.boost.org/LICENSE_1_0.txt) ] |
| [/ Home at http://www.boost.org/libs/scope_exit ] |
| |
| [library Boost.ScopeExit |
| [quickbook 1.5] |
| [version 1.1.0] |
| [copyright 2006-2012 Alexander Nasonov, Lorenzo Caminiti] |
| [purpose execute arbitrary code at scope exit] |
| [license |
| Distributed under the Boost Software License, Version 1.0 |
| (see accompanying file LICENSE_1_0.txt or a copy at |
| [@http://www.boost.org/LICENSE_1_0.txt]) |
| ] |
| [authors |
| [Nasonov, Alexander] |
| [Caminiti <email>lorcaminiti@gmail.com</email>, Lorenzo] |
| ] |
| [category utility] |
| [id scope_exit] |
| [dirname scope_exit] |
| ] |
| |
| [def __Introduction__ [link scope_exit.introduction Introduction]] |
| [def __Getting_Started__ [link scope_exit.getting_started Getting Started]] |
| [def __Tutorial__ [link scope_exit.tutorial Tutorial]] |
| [def __No_Variadic_Macros__ [link scope_exit.no_variadic_macros No Variadic Macros]] |
| [def __Reference__ [@reference.html Reference]] |
| [def __Boost_ScopeExit__ [link scope_exit Boost.ScopeExit]] |
| [def __Boost_Lambda__ [@http://www.boost.org/libs/lambda Boost.Lambda]] |
| [def __Boost_Phoenix__ [@http://www.boost.org/libs/phoenix Boost.Phoenix]] |
| [def __Boost_Typeof__ [@http://www.boost.org/libs/typeof Boost.Typeof]] |
| [def __typeof_emulation__ [@http://www.boost.org/libs/typeof type-of emulation]] |
| [def __Boost_Preprocessor__ [@http://www.boost.org/libs/preprocessor Boost.Preprocessor]] |
| [def __Boost_Config__ [@http://www.boost.org/libs/config Boost.Config]] |
| [def __Boost_PointerContainer__ [@http://www.boost.org/libs/ptr_container Boost.PointerContainer]] |
| [def __Boost_Multi_Index__ [@http://www.boost.org/libs/multi_index Boost.Multi-Index]] |
| [def __ScopeGuard__ [@http://www.ddj.com/dept/cpp/184403758 ScopeGuard]] |
| [def __D__ [@http://www.digitalmars.com/d/index.html D]] |
| [def __D_scope_exit__ [@http://www.digitalmars.com/d/2.0/statement.html#ScopeGuardStatement scope(exit)]] |
| [def __RAII__ [@http://www.research.att.com/~bs/glossary.html#Gresource-acquisition-is-initialization RAII]] |
| [def __strong_guarantee__ [@http://www.research.att.com/~bs/glossary.html#Gstrong-guarantee strong guarantee]] |
| |
| [import ../test/world.cpp] |
| [import ../test/world_seq.cpp] |
| [import ../test/world_checkpoint.cpp] |
| [import ../test/world_this.cpp] |
| [import ../test/world_void.cpp] |
| [import ../test/world_checkpoint_all.cpp] |
| [import ../test/world_tpl.cpp] |
| [import ../test/same_line.cpp] |
| [import ../example/try_catch.cpp] |
| [import ../example/scope_guard.cpp] |
| [import ../example/world_cxx11_lambda.cpp] |
| |
| This library allows to execute arbitrary code when the enclosing scope exits. |
| |
| [section Introduction] |
| |
| Nowadays, every C++ developer is familiar with the Resource Acquisition Is Initialization (__RAII__) technique. |
| It binds resource acquisition and release to initialization and destruction of a variable that holds the resource. |
| There are times when writing a special class for such a variable is not worth the effort. |
| This is when __Boost_ScopeExit__ comes into play. |
| |
| Programmers can put resource acquisition directly in their code and next to it, they can write code that releases the resource using this library. |
| For example (see also [@../../test/world.cpp =world.cpp=]): |
| [footnote |
| Older versions of this library used a __Boost_Preprocessor__ sequence to specify the list of captured variables. |
| While maintaining full backward compatibility, it is now possible to specify the captured variables also using a comma-separated list (which is the preferred syntax). |
| See the __No_Variadic_Macros__ section for more information. |
| ] |
| |
| [world] |
| |
| [endsect] |
| |
| [section Getting Started] |
| |
| This section explains how to setup a system to use this library. |
| |
| [section This Documentation] |
| |
| Programmers should have enough knowledge to use this library after reading the __Introduction__, __Getting_Started__, and __Tutorial__ sections. |
| The __Reference__ section can be consulted at a later point for quick reference. |
| All the other sections of this documentation can be considered optional. |
| |
| Some footnotes are marked by the word "*Rationale*". |
| They explain reasons behind decisions made during the design and implementation of this library. |
| |
| In most of the examples presented in this documentation, the Boost.Detail/LightweightTest (=boost/detail/lightweight_test.hpp=) macro `BOOST_TEST` is used to check correctness conditions. |
| The `BOOST_TEST` macro is conceptually similar to `assert` but a failure of the checked condition does not abort the program, instead it makes `boost::report_errors` return a non-zero program exit code. |
| [footnote |
| *Rationale.* |
| Using Boost.Detail/LightweightTest allows to add the examples to the library regression tests so to make sure that they always compile and run correctly. |
| ] |
| |
| [endsect] |
| |
| [section Compilers and Platforms] |
| |
| The authors originally developed and tested the library on GNU Compiler Collection (GCC) C++ 3.3, 3.4, 4.1, 4.2, 4.5.3 (with and without C++11 features [^-std=c++0x]), Microsoft Visual C++ (MSVC) 8.0, and Intel 10.1 under Linux, Cygwin, and Windows 7. |
| However, this library should be usable on any compiler that supports __Boost_Typeof__ except: |
| |
| * MSVC 7.1 and 8.0 fail to link if a function with __Boost_ScopeExit__ is included by multiple translation units. |
| * GCC 3.3 cannot compile __Boost_ScopeExit__ inside a template (see [@http://lists.boost.org/Archives/boost/2007/02/116235.php] for details). |
| |
| See the library [@http://www.boost.org/development/tests/release/developer/scope_exit.html regression test results] for detailed information on supported compilers and platforms. |
| Check the library regression test [@../../test/Jamfile.v2 =Jamfile.v2=] for any special configuration that might be required for a specific compiler. |
| |
| [endsect] |
| |
| [section Installation] |
| |
| This library is composed of header files only. |
| Therefore there is no pre-compiled object file which needs to be installed. |
| Programmers can simply instruct the compiler where to find the library header files (`-I` option on GCC, `/I` option on MSVC, etc) and compile code using the library. |
| |
| The library implementation uses __Boost_Typeof__ to automatically deduce the types of the __Boost_ScopeExit__ captured variables (see the __Tutorial__ section). |
| In order to compile code in __typeof_emulation__ mode, all types should be properly registered using `BOOST_TYPEOF_REGISTER_TYPE` and `BOOST_TYPEOF_REGISTER_TEMPLATE`, or appropriate __Boost_Typeof__ headers should be included (see the source code of most examples presented in this documentation). |
| |
| [endsect] |
| |
| [endsect] |
| |
| [section Tutorial] |
| |
| This section illustrates how to use this library. |
| |
| [section Capturing Variables] |
| |
| Imagine that we want to make many modifications to data members of some `world` class in its `world::add_person` member function. |
| We start with adding a new `person` object to a vector of persons: |
| |
| void world::add_person(person const& a_person) { |
| bool commit = false; |
| |
| persons_.push_back(a_person); // (1) direct action |
| ... |
| |
| Some operations down the road may throw an exception and all changes to involved objects should be rolled back. |
| This all-or-nothing semantic is also known as __strong_guarantee__. |
| |
| In particular, the last added person must be deleted from `persons_` if the function throws. |
| All we need is to define a delayed action (release of a resource) right after the direct action (resource acquisition). |
| For example (see also [@../../test/world.cpp =world.cpp=]): |
| |
| [world] |
| |
| The block below point =(1)= is a __Boost_ScopeExit__ declaration. |
| Unlike point =(1)=, an execution of the __Boost_ScopeExit__ body will be delayed until the end of the current scope. In this case it will be executed either after point =(4)= or on any exception. |
| (On various versions of the GCC compiler, it is necessary to use [macroref BOOST_SCOPE_EXIT_TPL] instead of [macroref BOOST_SCOPE_EXIT] within templates, see later in this section for details.) |
| |
| The __Boost_ScopeExit__ declaration starts with the [macroref BOOST_SCOPE_EXIT] macro invocation which accepts a comma-separated list of captured variables (a __Boost_Preprocessor__ sequence is also accepted for compilers that do not support variadic macros and for backward compatibility with older versions of this library, see the __No_Variadic_Macros__ section). |
| If a capture starts with the ampersand sign `&`, a reference to the captured variable will be available inside the __Boost_ScopeExit__ body; otherwise, a copy of the variable will be made after the __Boost_ScopeExit__ declaration at point =(1)= and only the copy will be available inside the body (in this case, the captured variable's type must be [@http://www.boost.org/doc/libs/release/doc/html/CopyConstructible.html `CopyConstructible`]). |
| |
| In the example above, the variables `commit` and `persons_` are captured by reference because the final value of the `commit` variable should be used to determine whether to execute rollback actions or not, and the action should modify the `persons_` object, not its copy. |
| This is the most common case but passing a variable by value is sometimes useful as well. |
| |
| Finally, the end of the __Boost_ScopeExit__ body must be marked by the [macroref BOOST_SCOPE_EXIT_END] macro which must follow the closing curly bracket `}` of the __Boost_ScopeExit__ body. |
| |
| [important |
| In order to comply with the [@http://www.stlport.org/doc/exception_safety.html STL exception safety requirements], the __Boost_ScopeExit__ body must never throw (because the library implementation executes the body within a destructor call). |
| This is true for all __Boost_ScopeExit__ macros (including [macroref BOOST_SCOPE_EXIT_TPL] and [macroref BOOST_SCOPE_EXIT_ALL] seen below) on both C++03 and C++11. |
| ] |
| |
| Consider a more complex example where `world::add_person` can save intermediate states at some point and roll back to the last saved state. |
| We use `person::evolution_` to store a version of the changes and increment it to cancel all rollback actions associated with those changes. |
| If we pass a current value of `evolution_` stored in the `checkpoint` variable by value, it remains unchanged within the __Boost_ScopeExit__ body so we can compare it with the final value of `evolution_`. |
| If the latter was not incremented since we saved it, the rollback action inside the __Boost_ScopeExit__ body should be executed. |
| For example (see also [@../../test/world_checkpoint.cpp =world_checkpoint.cpp=]): |
| |
| [world_checkpoint] |
| |
| When multiple __Boost_ScopeExit__ blocks are declared within the same enclosing scope, the __Boost_ScopeExit__ bodies are executed in the reversed order of their declarations. |
| |
| [endsect] |
| |
| [section Capturing The Object `this`] |
| |
| Within a member function, it is also possible to capture the object `this`. |
| However, the special symbol `this_` must be used instead of `this` in the __Boost_ScopeExit__ declaration and body to capture and access the object. |
| For example (see also [@../../test/world_this.cpp =world_this.cpp=]): |
| |
| [world_this] |
| |
| It is not possible to capture the object `this_` by reference because C++ does not allow to take a reference to `this`. |
| If the enclosing member function is constant then the captured object will also be constant, otherwise the captured object will be mutable. |
| |
| [endsect] |
| |
| [section Capturing No Variable] |
| |
| A __Boost_ScopeExit__ declaration can also capture no variable. |
| In this case, the list of captured variables is replaced by the `void` keyword (similarly to the C++ syntax that allows to declare a function with no parameter using [^['result-type function-name]]`(void)`). |
| [footnote |
| *Rationale.* |
| Unfortunately, it is not possible to simply invoke the __Boost_ScopeExit__ macro with no parameters as in `BOOST_SCOPE_EXIT()` because the C++ preprocessor cannot detect emptiness of a macro parameter when the parameter can start with a non-alphanumeric symbol (which is the case when capturing a variable by reference `&variable`). |
| ] |
| For example, this can be useful when the __Boost_ScopeExit__ body only needs to access global variables (see also [@../../test/world_void.cpp =world_void.cpp=]): |
| |
| [world_void] |
| |
| (Both compilers with and without variadic macros use this same syntax for capturing no variable, see the __No_Variadic_Macros__ section for more information.) |
| |
| [endsect] |
| |
| [section Capturing All Variables (C++11 Only)] |
| |
| On C++11 compliers, it is also possible to capture all the variables in scope without naming them one-by-one using the special macro [macroref BOOST_SCOPE_EXIT_ALL] instead of [macroref BOOST_SCOPE_EXIT]. |
| [footnote |
| *Rationale.* |
| The [macroref BOOST_SCOPE_EXIT_ALL] macro is only defined on C++11 compilers for which the __Boost_Config__ macro `BOOST_NO_CXX11_LAMBDAS` is not defined. |
| Using [macroref BOOST_SCOPE_EXIT_ALL] on C++03 compilers for which `BOOST_NO_CXX11_LAMBDAS` is defined will generate (possibly cryptic) compiler errors. |
| Note that a new macro [macroref BOOST_SCOPE_EXIT_ALL] needed to be introduced instead of reusing [macroref BOOST_SCOPE_EXIT] because `BOOST_SCOPE_EXIT(&)` and `BOOST_SCOPE_EXIT(=)` cannot be distinguished from `BOOST_SCOPE_EXIT(void)` or `BOOST_SCOPE_EXIT(this_)` using the C++ preprocessor given that the symbols `&` and `=` are neither prefxied nor postfixed by alphanumeric tokens (this is not an issue for [macroref BOOST_SCOPE_EXIT_ALL] which always has the non-alphanumeric `&` or `=` as the first capture so the first capture tokens are simply never compared with neither `void` nor `this_` for this macro). |
| ] |
| |
| Following the same syntax adopted by C++11 lambda functions, the [macroref BOOST_SCOPE_EXIT_ALL] macro accepts a comma-separated list of captures which must start with either `&` or `=` to capture all variables in scope respectively by reference or by value (note that no variable name is specified by these leading captures). |
| Additional captures of specific variables can follow the leading `&` or `=` and they will override the default reference or value captures. |
| For example (see also [@../../test/world_checkpoint_all.cpp =world_checkpoint_all.cpp=]): |
| |
| [world_checkpoint_all] |
| |
| The first __Boost_ScopeExit__ declaration captures all variables in scope by reference but the variable `checkpoint` and the object `this` which are explicitly captured by value (in particular, `p` and `persons_` are implicitly captured by reference here). |
| The second __Boost_ScopeExit__ declaration instead captures all variables in scope by value but `p` which is explicitly captured by reference (in particular, `checkpoint`, `prev_id`, and `this` are implicitly captured by value here). |
| |
| Note that the [macroref BOOST_SCOPE_EXIT_ALL] macro follows the C++11 lambda function syntax which is unfortunately different from the [macroref BOOST_SCOPE_EXIT] macro syntax. |
| In particular: |
| |
| # The [macroref BOOST_SCOPE_EXIT_ALL] macro cannot capture data members without capturing the object `this` while that is not the case for [macroref BOOST_SCOPE_EXIT]. |
| [footnote |
| At present, there seems to be some discussion to allow C++11 lambda functions to capture data members without capturing the object `this`. |
| If the C++11 standard were changed to allow this, the [macroref BOOST_SCOPE_EXIT_ALL] macro syntax could be extended to be a superset of the [macroref BOOST_SCOPE_EXIT] macro while keeping full backward compatibility. |
| ] |
| # The [macroref BOOST_SCOPE_EXIT_ALL] macro captures the object in scope using `this` instead of `this_`. |
| [footnote |
| On compilers that support the use of the `typename` outside templates as allowed by the C++11 standard, [macroref BOOST_SCOPE_EXIT_ALL] can use both `this` and `this_` to capture the object in scope (notably, this is not the case for the MSVC 10.0 compiler). |
| ] |
| # The [macroref BOOST_SCOPE_EXIT_ALL] body is terminated by a semicolon `;` instead than by the [macroref BOOST_SCOPE_EXIT_END] macro. |
| |
| If programmers define the configuration macro [macroref BOOST_SCOPE_EXIT_CONFIG_USE_LAMBDAS] then the [macroref BOOST_SCOPE_EXIT] macro implementation will use C++11 lamda functions and the [macroref BOOST_SCOPE_EXIT] macro will follow the same syntax of [macroref BOOST_SCOPE_EXIT_ALL] macro, which is the C++11 lambda function syntax. |
| However, [macroref BOOST_SCOPE_EXIT] will no longer be backward compatible and older code using [macroref BOOST_SCOPE_EXIT] might no longer compile (if data members were explicitly captured). |
| |
| [endsect] |
| |
| [section Template Workaround (GCC)] |
| |
| Various versions of the GCC compiler do not compile [macroref BOOST_SCOPE_EXIT] inside templates (see the __Reference__ section for more information). |
| As a workaround, [macroref BOOST_SCOPE_EXIT_TPL] should be used instead of [macroref BOOST_SCOPE_EXIT] in these cases. |
| [footnote |
| *Rationale.* |
| GCC versions compliant with C++11 do not present this issue and given that [macroref BOOST_SCOPE_EXIT_ALL] is only available on C++11 compilers, there is no need for a `BOOST_SCOPE_EXIT_ALL_TPL` macro. |
| ] |
| The [macroref BOOST_SCOPE_EXIT_TPL] macro has the exact same syntax of [macroref BOOST_SCOPE_EXIT]. |
| For example (see also [@../../test/world_tpl.cpp =world_tpl.cpp=]): |
| |
| [world_tpl] |
| |
| It is recommended to always use [macroref BOOST_SCOPE_EXIT_TPL] within templates so to maximize portability among different compilers. |
| |
| [endsect] |
| |
| [section Same Line Expansions] |
| |
| In general, it is not possible to expand the [macroref BOOST_SCOPE_EXIT], [macroref BOOST_SCOPE_EXIT_TPL], [macroref BOOST_SCOPE_EXIT_END], and [macroref BOOST_SCOPE_EXIT_ALL] macros multiple times on the same line. |
| [footnote |
| *Rationale.* |
| The library macros internally use `__LINE__` to generate unique identifiers. |
| Therefore, if the same macro is expanded more than on time on the same line, the generated identifiers will no longer be unique and the code will not compile. |
| (This restriction does not apply to MSVC and other compilers that provide the non-standard `__COUNTER__` macro.) |
| ] |
| |
| Therefore, this library provides additional macros [macroref BOOST_SCOPE_EXIT_ID], [macroref BOOST_SCOPE_EXIT_ID_TPL], [macroref BOOST_SCOPE_EXIT_END_ID], and [macroref BOOST_SCOPE_EXIT_ALL_ID] which can be expanded multiple times on the same line as long as programmers specify a unique identifiers as the macros' first parameters. |
| The unique identifier can be any token (not just numeric) that can be concatenated by the C++ preprocessor (e.g., `scope_exit_number_1_at_line_123`). |
| [footnote |
| Because there are restrictions on the set of tokens that the C++ preprocessor can concatenate and because not all compilers correctly implement these restrictions, it is in general recommended to specify unique identifiers as a combination of alphanumeric tokens. |
| ] |
| |
| The [macroref BOOST_SCOPE_EXIT_ID], [macroref BOOST_SCOPE_EXIT_ID_TPL], and [macroref BOOST_SCOPE_EXIT_ALL_ID] macros accept a capture list using the exact same syntax as [macroref BOOST_SCOPE_EXIT] and [macroref BOOST_SCOPE_EXIT_ALL] respectively. |
| For example (see also [@../../test/same_line.cpp =same_line.cpp=]): |
| |
| [same_line] |
| |
| As shown by the example above, the [macroref BOOST_SCOPE_EXIT_ID], [macroref BOOST_SCOPE_EXIT_ID_TPL], [macroref BOOST_SCOPE_EXIT_END_ID], and [macroref BOOST_SCOPE_EXIT_ALL_ID] macros are especially useful when it is necessary to invoke them multiple times within user-defined macros (because the C++ preprocessor expands all nested macros on the same line). |
| |
| [endsect] |
| |
| [endsect] |
| |
| [section:alternatives Annex: Alternatives] |
| |
| This section presents some alternative and related work to __Boost_ScopeExit__. |
| |
| [heading Try-Catch] |
| |
| This is an example of using a badly designed `file` class. |
| An instance of `file` does not close the file in its destructor, a programmer is expected to call the `close` member function explicitly. |
| For example (see also [@../../example/try_catch.cpp =try_catch.cpp=]): |
| |
| [try_catch_bad] |
| |
| Note the following issues with this approach: |
| |
| # The `passwd` object is defined outside of the `try` block because this object is required inside the `catch` block to close the file. |
| # The `passwd` object is not fully constructed until after the `open` |
| member function returns. |
| # If opening throws, the `passwd.close()` should not be called, hence the call to `passwd.is_open()`. |
| |
| The __Boost_ScopeExit__ approach does not have any of these issues. |
| For example (see also [@../../example/try_catch.cpp =try_catch.cpp=]): |
| |
| [try_catch_good] |
| |
| [heading RAII] |
| |
| __RAII__ is absolutely perfect for the `file` class introduced above. |
| Use of a properly designed `file` class would look like: |
| |
| try { |
| file passwd("/etc/passwd"); |
| // ... |
| } catch(...) { |
| std::clog << "could not get user info" << std::endl; |
| throw; |
| } |
| |
| However, using __RAII__ to build up a __strong_guarantee__ could introduce a lot of non-reusable __RAII__ types. |
| For example: |
| |
| persons_.push_back(a_person); |
| pop_back_if_not_commit pop_back_if_not_commit_guard(commit, persons_); |
| |
| The `pop_back_if_not_commit` class is either defined out of the scope or as a local class: |
| |
| class pop_back_if_not_commit { |
| bool commit_; |
| std::vector<person>& vec_; |
| // ... |
| ~pop_back_if_not_commit() { |
| if(!commit_) vec_.pop_back(); |
| } |
| }; |
| |
| In some cases __strong_guarantee__ can be accomplished with standard utilities: |
| |
| std::auto_ptr<Person> superman_ptr(new superman()); |
| persons_.push_back(superman_ptr.get()); |
| superman_ptr.release(); // persons_ successfully took ownership |
| |
| Or with specialized containers such as __Boost_PointerContainer__ or __Boost_Multi_Index__. |
| |
| [heading Scope Guards] |
| |
| Imagine that a new currency rate is introduced before performing a transaction (see also []): |
| |
| [scope_guard_decl] |
| |
| If the transaction does not complete, the currency must be erased from `rates`. |
| This can be done with __ScopeGuard__ and __Boost_Lambda__ (or __Boost_Phoenix__): |
| |
| using namespace boost::lambda; |
| |
| ON_BLOCK_EXIT( |
| if_(currency_rate_inserted && !_1) [ |
| bind( |
| static_cast< |
| std::map<std::string, double>::size_type |
| (std::map<std::string, double>::*)(std::string const&) |
| >(&std::map<std::string, double>::erase) |
| , &rates |
| , currency |
| ) |
| ] |
| , boost::cref(commit) |
| ); |
| |
| // ... |
| |
| commit = true; |
| |
| Note the following issues with this approach: |
| |
| # __Boost_Lambda__ expressions are hard to write correctly (e.g., overloaded functions must be explicitly casted, as demonstrated in the example above). |
| # The condition in the `if_` expression refers to `commit` variable indirectly through the `_1` placeholder reducing readability. |
| # Setting a breakpoint inside `if_[...]` requires in-depth knowledge of __Boost_Lambda__ and debugging techniques. |
| |
| This code will look much better with C++11 lambdas: |
| |
| ON_BLOCK_EXIT( |
| [currency_rate_inserted, &commit, &rates, ¤cy]() { |
| if(currency_rate_inserted && !commit) rates.erase(currency); |
| } |
| ); |
| |
| // ... |
| |
| commit = true; |
| |
| With __Boost_ScopeExit__ we can simply do the following (see also [@../../example/scope_guard.cpp =scope_guard.cpp=]): |
| |
| [scope_guard_exit] |
| |
| [heading The D Programming Language] |
| |
| __Boost_ScopeExit__ is similar to __D_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 [@http://www.gotw.ca/gotw/047.htm 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 __D_scope_exit__ and a `bool commit` variable (similarly to some examples presented in the __Tutorial__ section). |
| |
| [heading C++11 Lambdas] |
| |
| Using C++11 lambdas, it is relatively easy to implement the __Boost_ScopeExit__ construct. |
| For example (see also [@../../example/world_cxx11_lambda.cpp =world_cxx11_lambda.cpp=]): |
| |
| [world_cxx11_lambda] |
| |
| However, this library allows to program the __Boost_ScopeExit__ construct in a way that is portable between C++03 and C++11 compilers. |
| |
| [endsect] |
| |
| [section:no_variadic_macros Annex: No Variadic Macros] |
| |
| This section presents an alternative syntax for compilers without variadic macro support. |
| |
| [heading Sequence Syntax] |
| |
| Most modern compilers support variadic macros (notably, these include GCC, MSVC, and all C++11 compilers). |
| [footnote |
| A C++ compiler does not support variadic macros if the __Boost_Config__ macro `BOOST_NO_CXX11_VARIADIC_MACROS` is defined for that compiler. |
| ] |
| However, in the rare case that programmers need to use this library on a complier without variaidc macros, this library also allows to specify the capture list using a __Boost_Preprocessor__ sequence where tokens are separated by round parenthesis `()`: |
| |
| (capture1) (capture2) ... // All compilers. |
| |
| Instead of the comma-separated list that we have seen so far which requires variadic macros: |
| |
| capture1, capture2, ... // Only compilers with variadic macros. |
| |
| For example, the following syntax is accepted on all compilers with and without variadic macros (see also [@../../test/world_seq.cpp =world_seq.cpp=] and [@../../test/world.cpp =world.cpp=]): |
| |
| [table |
| [ [Boost.Preprocessor Sequence (All Compilers)] [Comma-Separated List (Variadic Macros Only)] ] |
| [ [[world_seq]] [[world]] ] |
| ] |
| |
| Note how the same macros accept both syntaxes on compilers with variadic macros and only the __Boost_Preprocessor__ sequence syntax on compilers without variadic macros. |
| Older versions of this library used to only support the __Boost_Preprocessor__ sequence syntax so this syntax is supported also for backward compatibility. |
| However, in the current version of this library and on compilers with variadic macros, the comma-separated syntax is preferred because it is more readable. |
| |
| Finally, an empty capture list is always specified using `void` on compilers with and without variaidc macros (see also [@../../test/world_void.cpp =world_void.cpp=]): |
| |
| [world_void] |
| |
| [heading Examples] |
| |
| For reference, the following is a list of most of the examples presented in this documentation reprogrammed using the __Boost_Preprocessor__ sequence syntax instead of comma-separated lists (in alphabetic order): |
| |
| [table |
| [ [Files] ] |
| [ [[@../../test/same_line_seq.cpp =same_line_seq.cpp=]] ] |
| [ [[@../../example/scope_guard_seq.cpp =scope_guard_seq.cpp=]] ] |
| [ [[@../../example/try_catch_seq.cpp =try_catch_seq.cpp=]] ] |
| [ [[@../../test/world_checkpoint_all_seq.cpp =world_checkpoint_all_seq.cpp=]] ] |
| [ [[@../../test/world_checkpoint_seq.cpp =world_checkpoint_seq.cpp=]] ] |
| [ [[@../../test/world_this_seq.cpp =world_this_seq.cpp=]] ] |
| [ [[@../../test/world_tpl_seq.cpp =world_tpl_seq.cpp=]] ] |
| ] |
| |
| [endsect] |
| |
| [xinclude reference.xml] |
| |
| [section Acknowledgements] |
| |
| Alexander Nasonov is the original library author. |
| |
| Lorenzo Caminiti added variadic macro support, capture of the object `this_`, empty captures using `void`, and `BOOST_SCOPE_EXIT_ALL`. |
| |
| Thanks to the following people (in chronological order): |
| |
| Maxim Yegorushkin for sharing code where he used a local struct to clean up resources; |
| |
| Andrei Alexandrescu for pointing out the __D_scope_exit__ construct of the __D__ programming language; |
| |
| Pavel Vozenilek and Maxim Yanchenko for reviews of early drafts of the library; |
| |
| Steven Watanabe for his valuable ideas; |
| |
| Jody Hagins for good comments that helped to significantly improve the documentation; |
| |
| Richard Webb for testing the library on MSVC compiler; |
| |
| Adam Butcher for a workaround to error C2355 when deducing the type of `this` on some MSVC versions. |
| |
| [endsect] |
| |