BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlb_scopeexit.h
Go to the documentation of this file.
1/// @file bdlb_scopeexit.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlb_scopeexit.h -*-C++-*-
8#ifndef INCLUDED_BDLB_SCOPEEXIT
9#define INCLUDED_BDLB_SCOPEEXIT
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlb_scopeexit bdlb_scopeexit
15/// @brief Provide a general-purpose proctor object for scope-exit logic.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlb
19/// @{
20/// @addtogroup bdlb_scopeexit
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlb_scopeexit-purpose"> Purpose</a>
25/// * <a href="#bdlb_scopeexit-classes"> Classes </a>
26/// * <a href="#bdlb_scopeexit-macros"> Macros </a>
27/// * <a href="#bdlb_scopeexit-description"> Description </a>
28/// * <a href="#bdlb_scopeexit-guard-vs-proctor"> Guard vs Proctor </a>
29/// * <a href="#bdlb_scopeexit-definitions"> Definitions </a>
30/// * <a href="#bdlb_scopeexit-further-explanation"> Further Explanation </a>
31/// * <a href="#bdlb_scopeexit-c-03-restrictions-when-exit-function-type-is-unknown"> C++03 Restrictions When Exit Function Type Is Unknown </a>
32/// * <a href="#bdlb_scopeexit-memory-allocation-and-relationship-with-bde-allocators"> Memory Allocation and Relationship with BDE Allocators </a>
33/// * <a href="#bdlb_scopeexit-notes"> Notes </a>
34/// * <a href="#bdlb_scopeexit-usage-examples"> Usage Examples </a>
35/// * <a href="#bdlb_scopeexit-example-1-using-a-scope-exit-proctor-in-c-11-or-later"> Example 1: Using a Scope Exit Proctor in C++11 or later </a>
36/// * <a href="#bdlb_scopeexit-example-2-using-a-scope-exit-guard-in-c-03"> Example 2: Using a Scope Exit Guard in C++03 </a>
37/// * <a href="#bdlb_scopeexit-example-3-unknown-exit-function-type-in-c-03"> Example 3: Unknown Exit Function Type In C++03 </a>
38/// * <a href="#bdlb_scopeexit-example-4-using-the-scope-exit-proctor-macro"> Example 4: Using the Scope Exit Proctor Macro </a>
39/// * <a href="#bdlb_scopeexit-example-5-using-the-scope-exit-guard-macro"> Example 5: Using the Scope Exit Guard Macro </a>
40///
41/// # Purpose {#bdlb_scopeexit-purpose}
42/// Provide a general-purpose proctor object for scope-exit logic.
43///
44/// # Classes {#bdlb_scopeexit-classes}
45///
46/// - bdlb::ScopeExit: executes a function upon destruction
47/// - bdlb::ScopeExitAny: an alias to `ScopeExit<bsl::function<void()>>`
48/// - bdlb::ScopeExitUtil: C++11 or later factory method for creating guards
49///
50/// # Macros {#bdlb_scopeexit-macros}
51///
52/// - BDLB_SCOPEEXIT_GUARD: creates a scope guard using an exit function
53/// - BDLB_SCOPEEXIT_PROCTOR: creates a scope proctor from name and exit function
54///
55/// @see
56/// P0052R6 - Generic Scope Guard and RAII Wrapper for the Standard Library
57/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0052r6.pdf
58///
59/// # Description {#bdlb_scopeexit-description}
60///
61/// This component provides a class template mechanism `bdlb::ScopeExit`, that
62/// will invoke a client supplied function upon its destruction.
63/// `bdlb::ScopeExit` is intended to facilitate creating scoped-proctors
64/// (similar to those found in {`bslma`}) that run a user-specified exit
65/// function upon their destruction, unless `release()`-d. The primary purpose
66/// of such a proctor is to execute a guaranteed undo of some operation in case
67/// the complete chain of operations was not successful (exception thrown or
68/// early return). The proctor may also be used as a guard to unconditionally
69/// run its exit function upon exiting a scope, however for such guards
70/// dedicated classes are highly recommended (see also {Guard vs Proctor}. In
71/// case of a sufficiently functional C++11 or later platform this component
72/// also defines a utility `bdlb::ScopeExitUtil` containing a factory method for
73/// creating `bdlb::ScopeExit` objects (`makeScopeExit`). This component also
74/// defines a type alias `bdlb::ScopeExitAny` that is used in C++03 code to
75/// create a proctor where the type of the exit function is not known (for
76/// example it is the result of a bind expression). Finally, this component
77/// defines two macros that allow creating the `bdlb::ScopeExit` objects,
78/// without mentioning the exit function type, in a uniform way for platforms
79/// limited to C++03 and those supporting sufficiently functional C++11 or
80/// later, but with a more efficient implementation for the latter. The first
81/// macro, `BDLB_SCOPEEXIT_PROCTOR` creates a scope proctor with a given
82/// variable name and exit function. The second macro, `BDLB_SCOPEEXIT_GUARD`
83/// creates a scope guard variable of unspecified name given only an exit
84/// function argument. See also {Guard vs Proctor}, and {C++03 Restrictions
85/// When Exit Function Type is Unknown}.
86///
87/// ## Guard vs Proctor {#bdlb_scopeexit-guard-vs-proctor}
88///
89///
90/// Guard and Proctor are terminology used by BDE methodology (see below).
91/// Because `bdlb::ScopeExit` is so general (its exit function is provided by
92/// the user) it can be used both as a Guard and as a Proctor. Below are the
93/// BDE definitions followed by an explanation of how they apply to this
94/// component.
95///
96/// ### Definitions {#bdlb_scopeexit-definitions}
97///
98///
99/// A (scoped) Guard is an object that maintains control over an associated
100/// resource (often acquired on construction) and releases that control when the
101/// Guard is destroyed (typically at scope exit -- either normally or because an
102/// exception was thrown). The guard may provide an explicit release method,
103/// but -- unlike a Proctor -- such a release method is not commonly used.
104///
105/// A Proctor is a special kind of guard intended to restore a valid state under
106/// abnormal circumstances (e.g., a thrown exception), until a valid state is
107/// restored normally, after which the Proctor's responsibility is explicitly
108/// released by its client. The Proctor must provide a mechanism to release the
109/// resource from management, and -- unlike a standard Guard -- its management
110/// responsibility is typically released prior to its destruction.
111///
112/// ### Further Explanation {#bdlb_scopeexit-further-explanation}
113///
114///
115/// A Guard controls the lifetime a resource, it owns it during the resource's
116/// complete lifetime, and its purpose is to free up that resource once the work
117/// that needed it is done. Guards may provide a `release` method for "off
118/// label use" in case the responsibility for freeing up the resource is
119/// transferred to some other code, but it is not its common use.
120///
121/// A Proctor is commonly responsible for undoing changes when a locally
122/// non-recoverable error occurs. Proctors do not necessarily clean up
123/// resources (although they might, as part of restoring a valid state). When
124/// all goes well, Proctors do nothing, because when all the work is
125/// successfully completed the user code "deactivates" the Proctor (or Proctors)
126/// to "commit" the work by calling the `release` method.
127///
128/// ## C++03 Restrictions When Exit Function Type Is Unknown {#bdlb_scopeexit-c-03-restrictions-when-exit-function-type-is-unknown}
129///
130///
131/// There are two restrictions when using this component with C++03 and both
132/// are related to missing core language features.
133///
134/// The first restriction is related to `bdlb::ScopeExit` being a move-only
135/// type, and although this class tries its best to emulate move semantics,
136/// returning an instance of `bdlb::ScopeExit` from a factory function is just
137/// not feasible under C++03. It is technically possible, but would require a
138/// lot of boilerplate code on the user side, making the use of the component
139/// way too cumbersome to use under C++03.
140///
141/// The second restriction is caused by the absence of the type-deducing `auto`
142/// keyword in C++03. Although we can deduce the type of the exit function in
143/// the factory method, without the type deduction capabilities provided by
144/// `auto` we cannot turn that return type into the type of a variable.
145///
146/// For the above reasons we do not generate or use a factory method in C++03
147/// but rely on `bsl::function<void()>` (as described below) to define a type
148/// that is able to store and call any exit function.
149///
150/// In case the type of the exit function is known to the programmer (see
151/// {Example 2: Using a Scope Exit Guard In C++03}) it is possible to simply
152/// provide that type as the template argument for `bdlb::ScopeExit`. But if
153/// our exit function has an unknown type (such as is the result of a `bind`
154/// expression) we are facing the same above two restrictions (see also
155/// {Example 3: Unknown Exit Function Type In C++03}).
156///
157/// Given the C+03 restrictions, the following design decisions have been made:
158/// 1. Do not provide the utility and factory function when compiling with
159/// C++03.
160/// 2. Provide a type `bdlb::ScopeExitAny` that is an alias to
161/// `bdlb::ScopeExit<bsl::function<void()> >`. An instance of
162/// `bdlb::ScopeExitAny` can be created without having to name the type of
163/// the exit function it is constructed from because `bsl::function`
164/// provides type erasure. The downside is the runtime performance cost of
165/// type erasure (virtual function call that might inhibit inlining) and
166/// potential memory allocation for stored arguments - all of which are the
167/// cost of using `bsl::function`.
168/// 3. Provide `BDLB_SCOPEEXIT_PROCTOR` and `BDLB_SCOPEEXIT_GUARD` macros that
169/// hide the difference between using a legacy C++03 `bdlb::ScopeExitAny`,
170/// or C++ `auto` type deduction from the factory function call. The macros
171/// thereby will select the most efficient `bdlb::ScopeExit` type that is
172/// feasible on the given compiler platform without having to specify the
173/// exact type of the exit function (the template parameter to
174/// `bdlb::ScopeExit`).
175///
176/// ## Memory Allocation and Relationship with BDE Allocators {#bdlb_scopeexit-memory-allocation-and-relationship-with-bde-allocators}
177///
178///
179/// The exit function is created as a member of the guard object, so no memory
180/// is allocated for storing it. However, if the exit function copy or move
181/// constructors require memory allocation, that memory is supplied by the
182/// currently installed default allocator. Currently this component does not
183/// support custom allocators. The main use-case of a guard object is to be
184/// created on the stack and automatic variables are supposed to use the
185/// default allocator, therefore no allocator support was added.
186///
187/// ## Notes {#bdlb_scopeexit-notes}
188///
189///
190/// This component has been inspired by P0052R6 a since not-adopted ISO C++
191/// Library proposal, but has been extended to support C++03, BDE methodology,
192/// and attributes.
193///
194/// ## Usage Examples {#bdlb_scopeexit-usage-examples}
195///
196///
197/// This section illustrates intended use of this component.
198///
199/// ### Example 1: Using a Scope Exit Proctor in C++11 or later {#bdlb_scopeexit-example-1-using-a-scope-exit-proctor-in-c-11-or-later}
200///
201///
202/// In this example we assume a C++ compiler supporting sufficiently functional
203/// C++11 or later. Suppose we are creating a simple database that stores names
204/// and their associated addresses and we store the names and addresses in two
205/// separate tables. While adding data, these tables may fail the insertion,
206/// in which case we need to roll back the already inserted data, such as if we
207/// inserted the address first, we need to remove it if insertion of the
208/// associated name fails.
209///
210/// First, we emulate our database access with the following simple functions:
211/// @code
212/// int removedAddressId = 0;
213/// int insertAddress(const char *address)
214/// {
215/// (void)address;
216/// return (0 == removedAddressId ? 2 : 3);
217/// }
218///
219/// int insertCustomer(const char *name, int addressId)
220/// {
221/// (void)name;
222/// (void)addressId;
223/// if (0 == removedAddressId) throw 5; // Simulate failure once
224/// return 7;
225/// }
226///
227/// void removeAddress(int id)
228/// {
229/// removedAddressId = id;
230/// }
231/// @endcode
232/// Next, we draw up our complex, customer-creating function signature:
233/// @code
234/// int addCustomer11(const char *name, const char *address)
235/// {
236/// @endcode
237/// Then we implement it, starting by inserting the address:
238/// @code
239/// const int addressId = insertAddress(address);
240/// @endcode
241/// Our dummy function returns 42, indicating successful address insertion.
242///
243/// Next, we create a proctor to remove the already inserted address if the name
244/// insertion fails:
245/// @code
246/// auto addressProctor = bdlb::ScopeExitUtil::makeScopeExit(
247/// [=](@ref bdlb_scopeexit) { removeAddress(addressId); });
248/// @endcode
249/// Then, we attempt to insert the name:
250/// @code
251/// const int custId = insertCustomer(name, addressId);
252/// @endcode
253/// As our dummy `insertCustomer` function will fail first time by throwing an
254/// exception (when `removedAddressId` is zero) we exit this function to the
255/// caller's error handling `catch` clause. While exiting the function due to
256/// the exception, the local stack is unwound. The non-trivial destructors of
257/// local variables are invoked (in the opposite order of their creation). In
258/// this case, the destructor of `addressProctor` invokes its exit function,
259/// saving our non-zero `addressId` value into the global `removedAddressId`
260/// variable.
261///
262/// On the second call to this function, because `removedAddressId` is now
263/// non-zero, `insertCustomer` will not fail, and we continue execution here.
264///
265/// Next, if the insertion succeeded we are done, so we need to release the
266/// proctor to make the address permanent, after which we can return the ID:
267/// @code
268/// addressProctor.release();
269///
270/// return custId; // RETURN
271/// }
272/// @endcode
273/// Now we can verify that a first attempt to add a customer fails with the
274/// "right" exception and that `removedAddressId` is the expected value:
275/// @code
276/// bool seenException = false;
277/// try {
278/// addCustomer11("Quibi", "6555 Barton Ave, Los Angeles, CA, 90038");
279/// }
280/// catch (int exceptionValue) {
281/// assert(5 == exceptionValue);
282/// seenException = true;
283/// }
284/// assert(seenException);
285/// assert(2 == removedAddressId);
286/// @endcode
287/// Finally we verify that calling `addCustomer11` again succeeds with the right
288/// identifier returned, and that `removedAddressId` does not change:
289/// @code
290/// assert(7 == addCustomer11("Plum Inc.", "1i Imagine Sq, Coppertin, CA"));
291/// assert(2 == removedAddressId);
292/// @endcode
293///
294/// ### Example 2: Using a Scope Exit Guard in C++03 {#bdlb_scopeexit-example-2-using-a-scope-exit-guard-in-c-03}
295///
296///
297/// Suppose we are in the same situation as in the C++11 or later example, but
298/// we have to create a solution that supports C++03 as well.
299///
300/// First, we have to hand-craft a functor that calls `removeAddress` with a
301/// given ID because C++03 does not support lambdas:
302/// @code
303/// class RemoveAddress {
304/// int d_id; // the identifier of the address (row) to remove
305///
306/// public:
307/// explicit RemoveAddress(int id)
308/// : d_id(id)
309/// {
310/// }
311///
312/// void operator()() const
313/// {
314/// removeAddress(d_id);
315/// }
316/// };
317/// @endcode
318/// Then, we implement the add customer function for C++03:
319/// @code
320/// int addCustomer03(const char *name, const char *address)
321/// {
322/// const int addressId = insertAddress(address);
323/// @endcode
324/// The code is almost the same code as was in `addCustomer11` (the
325/// implementation that requires sufficiently functional C++11 or later
326/// platform), except for the proctor variable definition.
327///
328/// Next, we define the proctor variable with an explicitly spelled out type
329/// (that uses the functor type template argument), and a functor object
330/// initialized with the identifier of the address to remove:
331/// @code
332/// bdlb::ScopeExit<RemoveAddress> addrProctor((RemoveAddress(addressId)));
333/// @endcode
334/// Notice the extra parentheses we had to use to avoid "the most vexing parse"
335/// (https://en.wikipedia.org/wiki/Most_vexing_parse) issue. Since we are in
336/// C++03, we cannot use (curly) brace initialization to avoid that issue.
337///
338/// Now, we can complete the rest of the `addCustomer03`, which is exactly the
339/// same as the corresponding part of the `addCustomer11` variant:
340/// @code
341/// const int custId = insertCustomer(name, addressId);
342/// addrProctor.release();
343///
344/// return custId; // RETURN
345/// }
346/// @endcode
347/// Finally, we can verify that both during the failing first attempt to add a
348/// customer to our imaginary database and the successful second attempt the
349/// `RemoveAddress` functor based proctor works just as well as the lambda based
350/// `addCustomer11` variant did:
351/// @code
352/// removedAddressId = 0;
353/// seenException = false;
354/// try {
355/// addCustomer03("Quibi", "6555 Barton Ave, Los Angeles, CA, 90038");
356/// }
357/// catch (int exceptionValue) {
358/// assert(5 == exceptionValue);
359/// seenException = true;
360/// }
361/// assert(seenException);
362/// assert(2 == removedAddressId);
363///
364/// assert(7 == addCustomer03("Plum Inc.", "1i Imagine Sq, Coppertin, CA"));
365/// assert(2 == removedAddressId);
366/// @endcode
367///
368/// ### Example 3: Unknown Exit Function Type In C++03 {#bdlb_scopeexit-example-3-unknown-exit-function-type-in-c-03}
369///
370///
371/// Suppose that we decide not to write a functor class for removing an address
372/// but use the function itself directly with `bdlf::BindUtil::bind` and that
373/// way keep the roll-back-code near the point of use like lambdas allow us in
374/// C++11 and later, albeit with a less elegant syntax.
375///
376/// First, we design our bind expression as
377/// `bdlf::BindUtil::bind(&removeAddress, addressId)`.
378///
379/// Then, we can even try it to see if it works as intended by calling the
380/// result of a bind expression using a constant for the address ID:
381/// @code
382/// removedAddressId = 0;
383/// bdlf::BindUtil::bind(&removeAddress, 11)();
384/// assert(11 == removedAddressId);
385/// @endcode
386/// Notice the subtle `()` after the bind expression. We immediately call it
387/// after creating it (then destroy it). We have to do it this way. We have no
388/// idea what its type is so we cannot make a variable for it.
389///
390/// Next, we create yet another customer adding function that differs only in
391/// its proctor definition from the `addCustomer11` variant:
392/// @code
393/// int addCustomerAny(const char *name, const char *address)
394/// {
395/// const int addressId = insertAddress(address);
396/// @endcode
397/// Because we do not know the type of our exit function (it is "some functor
398/// object of some type", created by `bind`) we have to use the `bsl::function`
399/// based `bdlb::ScopeExitAny`:
400/// @code
401/// bdlb::ScopeExitAny addressProctor(bdlf::BindUtil::bind(&removeAddress,
402/// addressId));
403/// @endcode
404/// Consult {C++03 Restrictions When Exit Function Type Is Unknown} to be aware
405/// what additional runtime costs this more compact code has compared to a
406/// "hand made" functor with a known type.
407///
408/// Note that since we have to take the address of a function to create the
409/// `bind`-expression-functor we cannot use this format with standard library
410/// functions (unless taking their address is explicitly allowed by the C++
411/// standard), and if `removeAddress` were an overloaded function the code would
412/// not compile as the compiler would not know which address we want.
413///
414/// The rest of the function is the same and omitted for brevity.
415///
416/// Finally, we can verify that `bind` and `bdlb::ScopeExitAny` based proctor
417/// works just as well:
418/// @code
419/// removedAddressId = 0;
420/// seenException = false;
421/// try {
422/// addCustomerAny("Quibi", "6555 Barton Ave, Los Angeles, CA, 90038");
423/// }
424/// catch (int exceptionValue) {
425/// assert(5 == exceptionValue);
426/// seenException = true;
427/// }
428/// assert(seenException);
429/// assert(2 == removedAddressId);
430///
431/// assert(7 == addCustomerAny("Plum Inc.", "1i Imagine Sq, Coppertin, CA"));
432/// assert(2 == removedAddressId);
433/// @endcode
434///
435/// ### Example 4: Using the Scope Exit Proctor Macro {#bdlb_scopeexit-example-4-using-the-scope-exit-proctor-macro}
436///
437///
438/// Suppose we have to create portable code that will compile with C++03 as well
439/// as C++11 and later compilers. We also want our code to use the more
440/// efficient type-deducing `auto` with factory-method variant when compiled
441/// with a sufficiently functional C++11 or later compiler, and only fall back
442/// to the slower `bdlb::ScopeExitAny` solution on C++03 compilers.
443///
444/// We still need to use either functor (`RemoveAddress` in our examples) or a
445/// bind expression for the exit function because C++03 has no lambdas,
446/// therefore our portable code cannot use lambdas. But we *can* choose the
447/// easy-to-use `BDLB_SCOPEEXIT_PROCTOR` macro and not sprinkle the add customer
448/// function with `#ifdef` to see which proctor definition to use.
449///
450/// To keep things simple this component provides a single proctor macro
451/// instead of two macro names to remember (one for the case case when the type
452/// of the exit function is known and one when it isn't). In case the exit
453/// function name is known we can just directly use
454/// `bdlb::ScopeExit< --ExitFunctionType-- >` on any compiler.
455///
456/// First, we start the add customer function as usual:
457/// @code
458/// int addCustomerMacro(const char *name, const char *address)
459/// {
460/// const int addressId = insertAddress(address);
461/// @endcode
462/// Then, we define the proctor using a bind expression and the macro:
463/// @code
464/// BDLB_SCOPEEXIT_PROCTOR(proctor, bdlf::BindUtil::bind(&removeAddress,
465/// addressId));
466/// @endcode
467/// Alternatively, we could have also written a functor and write the shorter
468/// `BDLB_SCOPEEXIT_PROCTOR(proctor, RemoveAddress(addressId))` for the proctor.
469///
470/// The rest of the function is the same and omitted for brevity.
471///
472/// Finally, we can verify the easy proctor with the now customary code:
473/// @code
474/// removedAddressId = 0;
475/// seenException = false;
476/// try {
477/// addCustomerMacro("Quibi", "6555 Barton Ave, Los Angeles, CA, 90038");
478/// }
479/// catch (int exceptionValue) {
480/// assert(5 == exceptionValue);
481/// seenException = true;
482/// }
483/// assert(seenException);
484/// assert(2 == removedAddressId);
485///
486/// assert(7 == addCustomerMacro("Plum Inc.", "1i Imagine Sq, Coppertin, CA"));
487/// assert(2 == removedAddressId);
488/// @endcode
489///
490/// ### Example 5: Using the Scope Exit Guard Macro {#bdlb_scopeexit-example-5-using-the-scope-exit-guard-macro}
491///
492///
493/// Suppose that we are writing a printing system that is capable of printing
494/// out dynamic data structures that can contain numbers, strings, arrays, maps,
495/// etc. When printing out data we often have to print delimiters and find
496/// that it is really easy to forget to print the closing the delimiter. So we
497/// look for a simple way to automate them. We decide we don't want to change
498/// the printing of the opening delimiters, just have a way to automate the
499/// printing of the close delimiters without worrying about early returns or
500/// `break`, `continue`, or other control flow changes.
501///
502/// First, we create a functor type that prints closing delimiters:
503/// @code
504/// class CloseDelimPrinter {
505/// const char *d_closingChars_p; // held, not owned
506///
507/// public:
508/// explicit CloseDelimPrinter(const char *s)
509/// : d_closingChars_p(s)
510/// {
511/// }
512///
513/// void operator()() const
514/// {
515/// outStream << d_closingChars_p; // To a fixed stream for brevity
516/// }
517/// };
518/// @endcode
519/// Then, we can use the above functor and a scope exit guard to automate
520/// closing of delimiters in the printing functions:
521/// @code
522/// void printTemplateWithArgs(
523/// const bsl::string_view>& templateName,
524/// const bsl::vector<bsl::string_view>& args)
525/// {
526/// @endcode
527/// Next, we can move the printing of the opening delimiter and the closing one
528/// near each other in code, so it is clearly visible if an opened delimiter is
529/// closed:
530/// @code
531/// outStream << templateName << '<';
532/// BDLB_SCOPEEXIT_GUARD(CloseDelimPrinter(">"));
533/// @endcode
534/// The macro works in C++03 and C++11 and later, gives the guard variable a
535/// unique (but unspecified) name, adds an extra set of parentheses to take care
536/// of "the most vexing parse" and suppresses unused variable compiler warnings.
537/// The name for the guard variable created is unspecified. Because this is a
538/// guard meaning we do not need to call `release()` (unlike a proctor),
539/// therefore the name is unimportant.
540///
541/// Now, we can just print what goes inside the delimiters, and we are done:
542/// @code
543/// if (args.empty()) {
544/// // Safe to just return, the guard takes care of closing the '<'
545/// return; // RETURN
546/// }
547///
548/// typedef bsl::vector<bsl::string_view>::const_iterator Cit;
549///
550/// Cit cit = args.begin();
551/// outStream << *cit; // Print first argument
552/// ++cit;
553///
554/// for (;cit != args.end(); ++cit) {
555/// outStream << ", " << *cit; // Print subsequent argument
556/// }
557///
558/// const bsl::string_view last = *(args.end() - 1);
559/// if (last.back() == '>') {
560/// outStream << ' ';
561/// }
562/// }
563/// @endcode
564/// Finally, we can print some templates and verify that the argument
565/// delimiters are closed:
566/// @code
567/// bsl::vector<bsl::string_view> targs;
568/// printTemplateWithArgs("TypeList", targs);
569/// assert(outStreamContent() == "TypeList<>");
570///
571/// targs.push_back("bsl::string_view");
572/// printTemplateWithArgs("bsl::vector", targs);
573/// assert(outStreamContent() == "bsl::vector<bsl::string_view>");
574///
575/// targs.push_back("bsl::vector<bsl::string_view>");
576/// printTemplateWithArgs("bsl::unordered_map", targs);
577/// assert(outStreamContent() ==
578/// "bsl::unordered_map<bsl::string_view, bsl::vector<bsl::string_view> >");
579/// @endcode
580/// @}
581/** @} */
582/** @} */
583
584/** @addtogroup bdl
585 * @{
586 */
587/** @addtogroup bdlb
588 * @{
589 */
590/** @addtogroup bdlb_scopeexit
591 * @{
592 */
593
594#include <bdlscm_version.h>
595
596#include <bsla_maybeunused.h>
597#include <bsla_nodiscard.h>
598
599#include <bslmf_assert.h>
600#include <bslmf_conditional.h>
601#include <bslmf_decay.h>
602#include <bslmf_enableif.h>
603#include <bslmf_isconvertible.h>
604#include <bslmf_isfunction.h>
606#include <bslmf_ispointer.h>
607#include <bslmf_issame.h>
608#include <bslmf_movableref.h>
609#include <bslmf_removepointer.h>
610#include <bslmf_util.h>
611
612#include <bsl_functional.h>
613
614#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
615 #include <bsl_type_traits.h>
616#endif
617#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
618 #include <bsl_utility.h> // 'bsl::move'
619#endif
620
621#include <bsls_buildtarget.h>
623#include <bsls_keyword.h>
624#include <bsls_platform.h>
625#include <bsls_util.h>
626
627// ============================================================================
628// MACROS
629// ============================================================================
630
631#ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
633 // 'BSLS_COMPILERFEATURES_CPLUSPLUS >= 201103L' is implied here.
634
635 /// This macro determines if we have a sufficiently functional C++11 or
636 /// later compiler so the type-deducing `auto` with factory-method can
637 /// be compiled and works as expected. When the macro is not defined
638 /// (C++03 form) no utility `struct` (therefore no factory method) will
639 /// be defined by this component and the variable definition macros (for
640 /// Proctor and Guard) will use `bdlb::ScopeExitAny`. When this macro
641 /// is defined (C++11 or later that has sufficiently operation rvalue
642 /// references and type-deducing `auto` keyword implementation) the
643 /// factory method and its utility `struct` will be defined and the
644 /// variable definition macros will use `auto` to determine the type of
645 /// the `bdlb::ScopeExit` variable. This macro is only internally in
646 /// this component header and therefore it is undefined at the end of
647 /// the file.
648 #define BDLB_SCOPEEXIT_USES_MODERN_CPP
649#endif
650
651#ifdef BDE_BUILD_TARGET_EXC
652 #define BDLB_SCOPEEXIT_NOEXCEPT_SPEC BSLS_KEYWORD_NOEXCEPT_SPECIFICATION
653#else
654 #define BDLB_SCOPEEXIT_NOEXCEPT_SPEC(...)
655#endif
656 // This macro is for internal use only and is undefined at the end of the
657 // file.
658
659/// Create a local variable with the specified `NAME` with a type that is an
660/// instantiation of `bdlb::ScopeExit` initialized with the specified `EXIT_FUNC`.
661///
662/// \note Note that the specific type of `bdlb::ScopeExit` used will
663/// depend on available language features.
664#ifdef BDLB_SCOPEEXIT_USES_MODERN_CPP
665 #define BDLB_SCOPEEXIT_PROCTOR(NAME, EXIT_FUNC) \
666 auto NAME{ BloombergLP::bdlb::ScopeExitUtil::makeScopeExit(EXIT_FUNC) }
667#else
668 #define BDLB_SCOPEEXIT_PROCTOR(NAME, EXIT_FUNC) \
669 BloombergLP::bdlb::ScopeExitAny NAME((EXIT_FUNC))
670#endif
671
672/// This macro is for use by `BDLB_SCOPEEXIT_GUARD` only to provide unique
673/// variable names. It is *not* undefined by the end of the file but its
674/// direct use is not supported under any circumstances.
675#define BDLB_SCOPEEXIT_PRIVATE_CAT(X, Y) BDLB_SCOPEEXIT_PRIVATE_CAT_IMP(X, Y)
676
677/// This macro is for use by `BDLB_SCOPEEXIT_GUARD` only to provide unique
678/// variable names. It is *not* undefined by the end of the file but its
679/// direct use is not supported under any circumstances.
680#define BDLB_SCOPEEXIT_PRIVATE_CAT_IMP(X, Y) X##Y
681
682/// This macro is for use by `BDLB_SCOPEEXIT_GUARD` only to provide unique
683/// variable names. It is *not* undefined by the end of the file but its
684/// direct use is not supported under any circumstances.
685#if defined(BSLS_PLATFORM_CMP_MSVC) || defined(BSLS_PLATFORM_CMP_GNU) || \
686 defined(BSLS_PLATFORM_CMP_CLANG)
687 // MSVC: The '__LINE__' macro breaks when '/ZI' is used (see Q199057 or
688 // KB199057). Fortunately the '__COUNTER__' extension provided by MSVC
689 // is even better. Since '__COUNTER__' is also available on all our
690 // supported newer C++ platforms (GNU g++ and clang) we use it there as
691 // well.
692 #define BDLB_SCOPEEXIT_PRIVATE_UNIQNUM __COUNTER__
693#else
694 #define BDLB_SCOPEEXIT_PRIVATE_UNIQNUM __LINE__
695#endif
696
697/// Create a local variable with a generated unique name and with a type
698/// that is an instantiation of `bdlb::ScopeExit` initialized with the specified `EXIT_FUNC`.
699///
700/// \note Note that the specific type of `bdlb::ScopeExit`
701/// used will depend on available language features.
702///
703/// \pre The behavior is undefined if this macro is used (expanded) more than once on the same source line.
704///
705/// \note Note that using this macro in another macro more than once
706/// is equivalent to using it more than once on the same source line.
707#define BDLB_SCOPEEXIT_GUARD(EXIT_FUNC) \
708 BSLA_MAYBE_UNUSED \
709 const BDLB_SCOPEEXIT_PROCTOR( \
710 BDLB_SCOPEEXIT_PRIVATE_CAT(bdlbScopeExitGuard_, \
711 BDLB_SCOPEEXIT_PRIVATE_UNIQNUM), \
712 EXIT_FUNC)
713
714// ============================================================================
715// CLASS TYPES
716// ============================================================================
717
718
719namespace bdlb {
720
721 // ===============
722 // class ScopeExit
723 // ===============
724
725/// `ScopeExit` is a general-purpose scope proctor class template that is
726/// intended to be used as an automatic (stack) variable that calls an exit
727/// function upon its destruction (when its scope is exited).
728///
729/// The template argument `EXIT_FUNC` shall be a function object type, or a
730/// pointer to a function. If `EXIT_FUNC` is an object type, it shall
731/// satisfy the requirements of *Destructible*, *Callable*, and *MoveConstructible* as specified by the ISO C++ standard.
732///
733/// \note Note that to
734/// fulfill the *MoveConstructible* constraint a type does not have to
735/// implement a move constructor. If it has a copy constructor, that will
736/// work fine as long at the move constructor is not deleted (or in case of C++03 emulated moves, `private`).
737///
738/// \pre The behavior is undefined if calling
739/// (the member instance of) `EXIT_FUNC` throws an exception (as it will be
740/// called from the destructor).
741template <class EXIT_FUNC>
743
744 private:
745 // TEMPLATE PARAMETER CONTRACT
749 typename bsl::remove_pointer<EXIT_FUNC>::type>::value);
750 // Only function pointers are allowed, no other pointers.
751
753 // Reference types are not allowed, only objects.
754
755 // We could check for more, but `is_destructible` needs full C++11
756 // `<type_traits>` support, and `is_invocable` is C++17 or later. So we
757 // skip checking these to avoid major conditional compilation clutter. The
758 // chance of passing non-destructible or non-callable `EXIT_FUNC` argument
759 // is low, and they will result in a reasonable error message.
760
761 private:
762 // PRIVATE TYPES
763
764 /// Shorter lines for more readable code.
766
767 private:
768 // PRIVATE DATA
769 EXIT_FUNC d_exitFunction; // A function pointer or functor to call
770 bool d_executeOnDestruction; // `false` if `release` was called
771
772 private:
773 // NOT IMPLEMENTED
774 ScopeExit(const ScopeExit&) BSLS_KEYWORD_DELETED; // No copying
775 ScopeExit& operator=(const ScopeExit&) BSLS_KEYWORD_DELETED; // No
776#ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES // assignment
777 ScopeExit& operator=(ScopeExit&&) BSLS_KEYWORD_DELETED; // at all.
778#endif
779
780 public:
781 // CREATORS
782
783 /// Create a `ScopeExit` object, which, upon its destruction will invoke
784 /// the specified `function` (or functor) unless its `release` method
785 /// was called. If `function` is copied into the `EXIT_FUNC` member,
786 /// and that copy throws an exception, invoke `function` and rethrow the
787 /// exception. If `EXIT_FUNC_PARAM` cannot be move converted to
788 /// `EXIT_FUNC` via no-throw means (either because such conversion does
789 /// not exist or it is not marked as non-throwing), `function` will
790 /// always be copied into the member. This constructor participates in
791 /// overload resolution only if `EXIT_FUNC_PARAM` is neither `EXIT_FUNC`
792 /// nor `bdlb::ScopeExit<EXIT_FUNC>` and `EXIT_FUNC_PARAM` is convertible to `EXIT_FUNC`.
793 ///
794 /// \pre The behavior is undefined if `function`
795 /// or the member instance of `EXIT_FUNC` throws an exception upon
796 /// invocation.
797 template <class EXIT_FUNC_PARAM>
798 explicit ScopeExit(
799 BSLS_COMPILERFEATURES_FORWARD_REF(EXIT_FUNC_PARAM) function,
800#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
801 // Enable explicit conversions on platforms where we can use
802 // `bsl::is_constructible`. Since this converting constructor itself is
803 // marked `explicit` we are not enabling anything extra by allowing
804 // `explicit` conversions when `EXIT_FUNC` is already explicitly
805 // convertible.
806 typename bsl::enable_if<
807 bsl::is_constructible< // Copy construct
808 EXIT_FUNC,
810 >::value ||
811 bsl::is_constructible< // Move construct
812 EXIT_FUNC,
814 >::value
815 >::type * = 0);
816#else
817 // `bsl::is_convertible` will not allow `explicit` conversions as we cannot
818 // check their existence in C++03 without running into a compilation error.
819 typename bsl::enable_if<
820 bsl::is_convertible< // "Copy convert"
822 EXIT_FUNC
823 >::value ||
824 bsl::is_convertible< // "Move convert"
826 EXIT_FUNC
827 >::value
828 >::type * = 0);
829#endif
830
831#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
832 /// Create a `ScopeExit` object, which, upon its destruction will invoke
833 /// the specified `function` unless the `release` method was called.
834 /// If `function` is copied into the `EXIT_FUNC` member, and that copy
835 /// throws an exception, invoke `function` and rethrow the exception.
836 ///
837 /// \pre The behavior is undefined if `function` or the member instance of `EXIT_FUNC` throws an exception upon invocation.
838 ///
839 /// \note Note that this
840 /// separate constructor for function pointers exists because without it
841 /// the forwarding logic in the templated constructor implementation
842 /// generates warnings about meaningless types generated.
843 explicit ScopeExit(void (*function)());
844#endif
845
846 /// If `bsl::is_nothrow_move_constructible<EXIT_FUNC>::value` is `true`
847 /// or `EXIT_FUNC` is a move-only type, move construct, otherwise, copy
848 /// construct the exit function from the specified `original`. If
849 /// construction succeeds, call `release()` on `original`.
851#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
854 || bsl::is_nothrow_copy_constructible<EXIT_FUNC>::value);
855#else
858#endif
859
860 /// Destroy this object. Execute the exit function unless `release()`
861 /// has been called on this object.
862 ~ScopeExit();
863
864 public:
865 // MANIPULATORS
866
867 /// Turn off the execution of the exit function of this object on
868 /// destruction.
869 void release();
870};
871
872#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
873// CLASS TEMPLATE DEDUCTION GUIDES
874template <class EXIT_FUNC_PARAM>
875explicit
876ScopeExit(BSLS_COMPILERFEATURES_FORWARD_REF(EXIT_FUNC_PARAM) function) ->
878#endif
879 // ====================
880 // typedef ScopeExitAny
881 // ====================
882
883/// `ScopeExitAny` is an alias to `ScopeExit<bsl::function<void()> >`,
884/// effectively making it a polymorphic scope exit type.
886
887#ifdef BDLB_SCOPEEXIT_USES_MODERN_CPP
888
889 // ===================
890 // class ScopeExitUtil
891 // ===================
892
893/// A utility that provides a factory function for sufficiently function
894/// C++11 or later platforms to create scope guards using the type-deducing
895/// `auto` keyword. Notice that the utility type does not exist on C++03
896/// platforms.
897///
898/// See @ref bdlb_scopeexit
899struct ScopeExitUtil {
900
901 // CLASS METHODS
902
903 /// Return a `ScopeExit` guard that uses the specified `function` as its
904 /// exit function, and has the decayed type of `function` (class type or
905 /// or function pointer type) as its exit function member type.
906 template <class EXIT_FUNC_PARAM>
908 static
910 makeScopeExit(EXIT_FUNC_PARAM&& function);
911};
912#endif // BDLB_SCOPEEXIT_USES_MODERN_CPP
913
914// ============================================================================
915// INLINE DEFINITIONS
916// ============================================================================
917
918 // ---------------
919 // class ScopeExit
920 // ---------------
921
922// CREATORS
923template <class EXIT_FUNC>
924template <class EXIT_FUNC_PARAM>
925inline
927 BSLS_COMPILERFEATURES_FORWARD_REF(EXIT_FUNC_PARAM) function,
928 typename bsl::enable_if<
929#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
930 bsl::is_constructible< // Copy construct
931 EXIT_FUNC,
933 >::value ||
934 bsl::is_constructible< // Move construct
935 EXIT_FUNC,
937 >::value
938#else
939 bsl::is_convertible< // "Copy convert"
941 EXIT_FUNC
942 >::value ||
943 bsl::is_convertible< // "Move convert"
945 EXIT_FUNC
946 >::value
947#endif
948 >::type *)
949#ifdef BDE_BUILD_TARGET_EXC
950try
951#endif
952#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
953: d_exitFunction(
955 typename bsl::conditional<
956 bsl::is_nothrow_constructible<EXIT_FUNC,
957 EXIT_FUNC_PARAM>::value ||
958 !bsl::is_constructible<
959 EXIT_FUNC,
960 const typename MoveUtil::RemoveReference<
961 EXIT_FUNC_PARAM>::type&
962 >::value,
963 EXIT_FUNC_PARAM,
964 const typename MoveUtil::RemoveReference<
965 EXIT_FUNC_PARAM>::type&
966 >::type
967 >(function))
968#else // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
969: d_exitFunction(BSLS_COMPILERFEATURES_FORWARD(EXIT_FUNC_PARAM, function))
970 // When we are unable to determine if it's safe to move the 'function'
971 // parameter or not (based on its type, using type traits), we forward the
972 // parameter in the usual manner, with the BDE-provided macro that picks
973 // the best forwarding possible on the given compiler. This prevents
974 // compilation errors in case the functor is a move-only object.
975#endif // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
976, d_executeOnDestruction(true)
977{
978}
979#ifdef BDE_BUILD_TARGET_EXC
980catch (...)
981{
982 MoveUtil::access(function)();
983}
984#endif
985
986#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
987template <class EXIT_FUNC>
988inline ScopeExit<EXIT_FUNC>::ScopeExit(void (*function)())
989#ifdef BDE_BUILD_TARGET_EXC
990try
991#endif
992: d_exitFunction(function)
993, d_executeOnDestruction(true)
994{
995}
996#ifdef BDE_BUILD_TARGET_EXC
997catch (...)
998{
999 function();
1000}
1001#endif
1002#endif // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
1003
1004template <class EXIT_FUNC>
1005inline
1007#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
1010 || bsl::is_nothrow_copy_constructible<EXIT_FUNC>::value)
1011#else
1014#endif
1015: d_exitFunction(MoveUtil::move_if_noexcept(
1016 MoveUtil::access(original).d_exitFunction))
1017, d_executeOnDestruction(true)
1018{
1019 MoveUtil::access(original).release();
1020}
1021
1022template <class EXIT_FUNC>
1023inline
1025{
1026 if (d_executeOnDestruction) {
1027 d_exitFunction();
1028 }
1029}
1030
1031// MANIPULATORS
1032template <class EXIT_FUNC>
1033inline
1035{
1036 d_executeOnDestruction = false;
1037}
1038
1039#ifdef BDLB_SCOPEEXIT_USES_MODERN_CPP
1040
1041 // -------------------
1042 // class ScopeExitUtil
1043 // -------------------
1044
1045// CLASS METHODS
1046template <class EXIT_FUNC_PARAM>
1047inline
1049ScopeExitUtil::makeScopeExit(EXIT_FUNC_PARAM&& function)
1050{
1052 bslmf::Util::forward<EXIT_FUNC_PARAM>(function));
1053}
1054
1055#endif // BDLB_SCOPEEXIT_USES_MODERN_CPP
1056
1057} // close package namespace
1058
1059
1060// ============================================================================
1061// TYPE TRAITS
1062// ============================================================================
1063
1064#ifndef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
1065// In case there is no reliable '<type_traits>' header we use 'bsl' a trait to
1066// mark our class no-throw-move-constructible, if the single member is.
1067
1068namespace bsl {
1069template <class EXIT_FUNC>
1070struct is_nothrow_move_constructible<BloombergLP::bdlb::ScopeExit<EXIT_FUNC> >
1072{};
1073} // close 'bsl' namespace
1074#endif
1075
1076#ifdef BDLB_SCOPEEXIT_USES_MODERN_CPP
1077#undef BDLB_SCOPEEXIT_USES_MODERN_CPP
1078#endif
1079
1080#ifdef BDLB_SCOPEEXIT_NOEXCEPT_SPEC
1081#undef BDLB_SCOPEEXIT_NOEXCEPT_SPEC
1082#endif
1083
1084#endif
1085
1086// ----------------------------------------------------------------------------
1087// Copyright 2018 Bloomberg Finance L.P.
1088//
1089// Licensed under the Apache License, Version 2.0 (the "License");
1090// you may not use this file except in compliance with the License.
1091// You may obtain a copy of the License at
1092//
1093// http://www.apache.org/licenses/LICENSE-2.0
1094//
1095// Unless required by applicable law or agreed to in writing, software
1096// distributed under the License is distributed on an "AS IS" BASIS,
1097// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1098// See the License for the specific language governing permissions and
1099// limitations under the License.
1100// ----------------------------- END-OF-FILE ----------------------------------
1101
1102/** @} */
1103/** @} */
1104/** @} */
Definition bdlb_scopeexit.h:742
void release()
Definition bdlb_scopeexit.h:1034
ScopeExit(bslmf::MovableRef< ScopeExit > original) BDLB_SCOPEEXIT_NOEXCEPT_SPEC(bsl ~ScopeExit()
Definition bdlb_scopeexit.h:1024
Forward declaration.
Definition bslstl_function.h:946
Definition bslmf_movableref.h:752
#define BDLB_SCOPEEXIT_NOEXCEPT_SPEC(...)
Definition bdlb_scopeexit.h:654
#define BSLA_NODISCARD_CPP17
Definition bsla_nodiscard.h:321
#define BSLA_NODISCARD
Definition bsla_nodiscard.h:320
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:231
#define BSLS_COMPILERFEATURES_FORWARD_REF(T)
Definition bsls_compilerfeatures.h:2343
#define BSLS_COMPILERFEATURES_FORWARD(T, V)
Definition bsls_compilerfeatures.h:2349
#define BSLS_COMPILERFEATURES_CPLUSPLUS
Definition bsls_compilerfeatures.h:1396
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:651
Definition bdlb_algorithmworkaroundutil.h:74
ScopeExit< bsl::function< void()> > ScopeExitAny
Definition bdlb_scopeexit.h:885
Definition bdlat_valuetypefunctions.h:939
Definition bslmf_conditional.h:123
Definition bslmf_enableif.h:530
Definition bslmf_isconvertible.h:875
Definition bslmf_isfunction.h:232
Definition bslmf_isnothrowmoveconstructible.h:361
Definition bslmf_ispointer.h:138
Definition bslmf_isreference.h:137
BloombergLP::bslmf::RemovePointer_Imp< t_TYPE >::Type type
Definition bslmf_removepointer.h:274
Definition bslmf_movableref.h:867
Definition bslmf_movableref.h:829
Definition bslmf_movableref.h:795
static BSLS_KEYWORD_CONSTEXPR const t_TYPE & forward(const t_TYPE &t) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_util.h:462