BDE 4.14.0 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
661/// `EXIT_FUNC`. Note that the specific type of `bdlb::ScopeExit` used will
662/// depend on available language features.
663#ifdef BDLB_SCOPEEXIT_USES_MODERN_CPP
664 #define BDLB_SCOPEEXIT_PROCTOR(NAME, EXIT_FUNC) \
665 auto NAME{ BloombergLP::bdlb::ScopeExitUtil::makeScopeExit(EXIT_FUNC) }
666#else
667 #define BDLB_SCOPEEXIT_PROCTOR(NAME, EXIT_FUNC) \
668 BloombergLP::bdlb::ScopeExitAny NAME((EXIT_FUNC))
669#endif
670
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_PLATFCORM_CMP_GNU) || \
686 defined(BSLS_PLATFCORM_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
699/// specified `EXIT_FUNC`. Note that the specific type of `bdlb::ScopeExit`
700/// used will depend on available language features. The behavior is
701/// undefined if this macro is used (expanded) more than once on the same
702/// source line. Note that using this macro in another macro more than once
703/// is equivalent to using it more than once on the same source line.
704#define BDLB_SCOPEEXIT_GUARD(EXIT_FUNC) \
705 BSLA_MAYBE_UNUSED \
706 const BDLB_SCOPEEXIT_PROCTOR( \
707 BDLB_SCOPEEXIT_PRIVATE_CAT(bdlbScopeExitGuard_, \
708 BDLB_SCOPEEXIT_PRIVATE_UNIQNUM), \
709 EXIT_FUNC)
710
711// ============================================================================
712// CLASS TYPES
713// ============================================================================
714
715
716namespace bdlb {
717
718 // ===============
719 // class ScopeExit
720 // ===============
721
722/// `ScopeExit` is a general-purpose scope proctor class template that is
723/// intended to be used as an automatic (stack) variable that calls an exit
724/// function upon its destruction (when its scope is exited).
725///
726/// The template argument `EXIT_FUNC` shall be a function object type, or a
727/// pointer to a function. If `EXIT_FUNC` is an object type, it shall
728/// satisfy the requirements of *Destructible*, *Callable*, and
729/// *MoveConstructible* as specified by the ISO C++ standard. Note that to
730/// fulfill the *MoveConstructible* constraint a type does not have to
731/// implement a move constructor. If it has a copy constructor, that will
732/// work fine as long at the move constructor is not deleted (or in case of
733/// C++03 emulated moves, `private`). The behavior is undefined if calling
734/// (the member instance of) `EXIT_FUNC` throws an exception (as it will be
735/// called from the destructor).
736template <class EXIT_FUNC>
738
739 private:
740 // TEMPLATE PARAMETER CONTRACT
744 typename bsl::remove_pointer<EXIT_FUNC>::type>::value);
745 // Only function pointers are allowed, no other pointers.
746
748 // Reference types are not allowed, only objects.
749
750 // We could check for more, but `is_destructible` needs full C++11
751 // `<type_traits>` support, and `is_invocable` is C++17 or later. So we
752 // skip checking these to avoid major conditional compilation clutter. The
753 // chance of passing non-destructible or non-callable `EXIT_FUNC` argument
754 // is low, and they will result in a reasonable error message.
755
756 private:
757 // PRIVATE TYPES
758
759 /// Shorter lines for more readable code.
761
762 private:
763 // PRIVATE DATA
764 EXIT_FUNC d_exitFunction; // A function pointer or functor to call
765 bool d_executeOnDestruction; // `false` if `release` was called
766
767 private:
768 // NOT IMPLEMENTED
769 ScopeExit(const ScopeExit&) BSLS_KEYWORD_DELETED; // No copying
770 ScopeExit& operator=(const ScopeExit&) BSLS_KEYWORD_DELETED; // No
771#ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES // assignment
772 ScopeExit& operator=(ScopeExit&&) BSLS_KEYWORD_DELETED; // at all.
773#endif
774
775 public:
776 // CREATORS
777
778 /// Create a `ScopeExit` object, which, upon its destruction will invoke
779 /// the specified `function` (or functor) unless its `release` method
780 /// was called. If `function` is copied into the `EXIT_FUNC` member,
781 /// and that copy throws an exception, invoke `function` and rethrow the
782 /// exception. If `EXIT_FUNC_PARAM` cannot be move converted to
783 /// `EXIT_FUNC` via no-throw means (either because such conversion does
784 /// not exist or it is not marked as non-throwing), `function` will
785 /// always be copied into the member. This constructor participates in
786 /// overload resolution only if `EXIT_FUNC_PARAM` is neither `EXIT_FUNC`
787 /// nor `bdlb::ScopeExit<EXIT_FUNC>` and `EXIT_FUNC_PARAM` is
788 /// convertible to `EXIT_FUNC`. The behavior is undefined if `function`
789 /// or the member instance of `EXIT_FUNC` throws an exception upon
790 /// invocation.
791 template <class EXIT_FUNC_PARAM>
792 explicit ScopeExit(
793 BSLS_COMPILERFEATURES_FORWARD_REF(EXIT_FUNC_PARAM) function,
794#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
795 // Enable explicit conversions on platforms where we can use
796 // `bsl::is_constructible`. Since this converting constructor itself is
797 // marked `explicit` we are not enabling anything extra by allowing
798 // `explicit` conversions when `EXIT_FUNC` is already explicitly
799 // convertible.
800 typename bsl::enable_if<
801 bsl::is_constructible< // Copy construct
802 EXIT_FUNC,
804 >::value ||
805 bsl::is_constructible< // Move construct
806 EXIT_FUNC,
808 >::value
809 >::type * = 0);
810#else
811 // `bsl::is_convertible` will not allow `explicit` conversions as we cannot
812 // check their existence in C++03 without running into a compilation error.
813 typename bsl::enable_if<
814 bsl::is_convertible< // "Copy convert"
816 EXIT_FUNC
817 >::value ||
818 bsl::is_convertible< // "Move convert"
820 EXIT_FUNC
821 >::value
822 >::type * = 0);
823#endif
824
825#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
826 /// Create a `ScopeExit` object, which, upon its destruction will invoke
827 /// the specified `function` unless the `release` method was called.
828 /// If `function` is copied into the `EXIT_FUNC` member, and that copy
829 /// throws an exception, invoke `function` and rethrow the exception.
830 /// The behavior is undefined if `function` or the member instance of
831 /// `EXIT_FUNC` throws an exception upon invocation. Note that this
832 /// separate constructor for function pointers exists because without it
833 /// the forwarding logic in the templated constructor implementation
834 /// generates warnings about meaningless types generated.
835 explicit ScopeExit(void (*function)());
836#endif
837
838 /// If `bsl::is_nothrow_move_constructible<EXIT_FUNC>::value` is `true`
839 /// or `EXIT_FUNC` is a move-only type, move construct, otherwise, copy
840 /// construct the exit function from the specified `original`. If
841 /// construction succeeds, call `release()` on `original`.
843#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
846 || bsl::is_nothrow_copy_constructible<EXIT_FUNC>::value);
847#else
850#endif
851
852 /// Destroy this object. Execute the exit function unless `release()`
853 /// has been called on this object.
854 ~ScopeExit();
855
856 public:
857 // MANIPULATORS
858
859 /// Turn off the execution of the exit function of this object on
860 /// destruction.
861 void release();
862};
863
864#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
865// CLASS TEMPLATE DEDUCTION GUIDES
866template <class EXIT_FUNC_PARAM>
867explicit
868ScopeExit(BSLS_COMPILERFEATURES_FORWARD_REF(EXIT_FUNC_PARAM) function) ->
870#endif
871 // ====================
872 // typedef ScopeExitAny
873 // ====================
874
875/// `ScopeExitAny` is an alias to `ScopeExit<bsl::function<void()> >`,
876/// effectively making it a polymorphic scope exit type.
878
879#ifdef BDLB_SCOPEEXIT_USES_MODERN_CPP
880
881 // ===================
882 // class ScopeExitUtil
883 // ===================
884
885/// A utility that provides a factory function for sufficiently function
886/// C++11 or later platforms to create scope guards using the type-deducing
887/// `auto` keyword. Notice that the utility type does not exist on C++03
888/// platforms.
889struct ScopeExitUtil {
890
891 // CLASS METHODS
892
893 /// Return a `ScopeExit` guard that uses the specified `function` as its
894 /// exit function, and has the decayed type of `function` (class type or
895 /// or function pointer type) as its exit function member type.
896 template <class EXIT_FUNC_PARAM>
898 static
900 makeScopeExit(EXIT_FUNC_PARAM&& function);
901};
902#endif // BDLB_SCOPEEXIT_USES_MODERN_CPP
903
904// ============================================================================
905// INLINE DEFINITIONS
906// ============================================================================
907
908 // ---------------
909 // class ScopeExit
910 // ---------------
911
912// CREATORS
913template <class EXIT_FUNC>
914template <class EXIT_FUNC_PARAM>
915inline
917 BSLS_COMPILERFEATURES_FORWARD_REF(EXIT_FUNC_PARAM) function,
918 typename bsl::enable_if<
919#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
920 bsl::is_constructible< // Copy construct
921 EXIT_FUNC,
923 >::value ||
924 bsl::is_constructible< // Move construct
925 EXIT_FUNC,
927 >::value
928#else
929 bsl::is_convertible< // "Copy convert"
931 EXIT_FUNC
932 >::value ||
933 bsl::is_convertible< // "Move convert"
935 EXIT_FUNC
936 >::value
937#endif
938 >::type *)
939#ifdef BDE_BUILD_TARGET_EXC
940try
941#endif
942#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
943: d_exitFunction(
945 typename bsl::conditional<
946 bsl::is_nothrow_constructible<EXIT_FUNC,
947 EXIT_FUNC_PARAM>::value ||
948 !bsl::is_constructible<
949 EXIT_FUNC,
950 const typename MoveUtil::RemoveReference<
951 EXIT_FUNC_PARAM>::type&
952 >::value,
953 EXIT_FUNC_PARAM,
954 const typename MoveUtil::RemoveReference<
955 EXIT_FUNC_PARAM>::type&
956 >::type
957 >(function))
958#else // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
959: d_exitFunction(BSLS_COMPILERFEATURES_FORWARD(EXIT_FUNC_PARAM, function))
960 // When we are unable to determine if it's safe to move the 'function'
961 // parameter or not (based on its type, using type traits), we forward the
962 // parameter in the usual manner, with the BDE-provided macro that picks
963 // the best forwarding possible on the given compiler. This prevents
964 // compilation errors in case the functor is a move-only object.
965#endif // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
966, d_executeOnDestruction(true)
967{
968}
969#ifdef BDE_BUILD_TARGET_EXC
970catch (...)
971{
972 MoveUtil::access(function)();
973}
974#endif
975
976#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
977template <class EXIT_FUNC>
978inline ScopeExit<EXIT_FUNC>::ScopeExit(void (*function)())
979#ifdef BDE_BUILD_TARGET_EXC
980try
981#endif
982: d_exitFunction(function)
983, d_executeOnDestruction(true)
984{
985}
986#ifdef BDE_BUILD_TARGET_EXC
987catch (...)
988{
989 function();
990}
991#endif
992#endif // BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
993
994template <class EXIT_FUNC>
995inline
997#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
1000 || bsl::is_nothrow_copy_constructible<EXIT_FUNC>::value)
1001#else
1004#endif
1005: d_exitFunction(MoveUtil::move_if_noexcept(
1006 MoveUtil::access(original).d_exitFunction))
1007, d_executeOnDestruction(true)
1008{
1009 MoveUtil::access(original).release();
1010}
1011
1012template <class EXIT_FUNC>
1013inline
1015{
1016 if (d_executeOnDestruction) {
1017 d_exitFunction();
1018 }
1019}
1020
1021// MANIPULATORS
1022template <class EXIT_FUNC>
1023inline
1025{
1026 d_executeOnDestruction = false;
1027}
1028
1029#ifdef BDLB_SCOPEEXIT_USES_MODERN_CPP
1030
1031 // -------------------
1032 // class ScopeExitUtil
1033 // -------------------
1034
1035// CLASS METHODS
1036template <class EXIT_FUNC_PARAM>
1037inline
1039ScopeExitUtil::makeScopeExit(EXIT_FUNC_PARAM&& function)
1040{
1042 bslmf::Util::forward<EXIT_FUNC_PARAM>(function));
1043}
1044
1045#endif // BDLB_SCOPEEXIT_USES_MODERN_CPP
1046
1047} // close package namespace
1048
1049
1050// ============================================================================
1051// TYPE TRAITS
1052// ============================================================================
1053
1054#ifndef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
1055// In case there is no reliable '<type_traits>' header we use 'bsl' a trait to
1056// mark our class no-throw-move-constructible, if the single member is.
1057
1058namespace bsl {
1059template <class EXIT_FUNC>
1060struct is_nothrow_move_constructible<BloombergLP::bdlb::ScopeExit<EXIT_FUNC> >
1062{};
1063} // close 'bsl' namespace
1064#endif
1065
1066#ifdef BDLB_SCOPEEXIT_USES_MODERN_CPP
1067#undef BDLB_SCOPEEXIT_USES_MODERN_CPP
1068#endif
1069
1070#ifdef BDLB_SCOPEEXIT_NOEXCEPT_SPEC
1071#undef BDLB_SCOPEEXIT_NOEXCEPT_SPEC
1072#endif
1073
1074#endif
1075
1076// ----------------------------------------------------------------------------
1077// Copyright 2018 Bloomberg Finance L.P.
1078//
1079// Licensed under the Apache License, Version 2.0 (the "License");
1080// you may not use this file except in compliance with the License.
1081// You may obtain a copy of the License at
1082//
1083// http://www.apache.org/licenses/LICENSE-2.0
1084//
1085// Unless required by applicable law or agreed to in writing, software
1086// distributed under the License is distributed on an "AS IS" BASIS,
1087// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1088// See the License for the specific language governing permissions and
1089// limitations under the License.
1090// ----------------------------- END-OF-FILE ----------------------------------
1091
1092/** @} */
1093/** @} */
1094/** @} */
Definition bdlb_scopeexit.h:737
void release()
Definition bdlb_scopeexit.h:1024
ScopeExit(bslmf::MovableRef< ScopeExit > original) BDLB_SCOPEEXIT_NOEXCEPT_SPEC(bsl ~ScopeExit()
Definition bdlb_scopeexit.h:1014
Forward declaration.
Definition bslstl_function.h:934
Definition bslmf_movableref.h:751
#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:229
#define BSLS_COMPILERFEATURES_FORWARD_REF(T)
Definition bsls_compilerfeatures.h:2012
#define BSLS_COMPILERFEATURES_FORWARD(T, V)
Definition bsls_compilerfeatures.h:2018
#define BSLS_COMPILERFEATURES_CPLUSPLUS
Definition bsls_compilerfeatures.h:1183
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_DELETED
Definition bsls_keyword.h:609
Definition bdlb_algorithmworkaroundutil.h:74
ScopeExit< bsl::function< void()> > ScopeExitAny
Definition bdlb_scopeexit.h:877
Definition bdlb_printmethods.h:283
Definition bslmf_conditional.h:120
Definition bslmf_enableif.h:525
Definition bslmf_isconvertible.h:867
Definition bslmf_isfunction.h:232
Definition bslmf_isnothrowmoveconstructible.h:358
Definition bslmf_ispointer.h:138
Definition bslmf_isreference.h:137
BloombergLP::bslmf::RemovePointer_Imp< t_TYPE >::Type type
Definition bslmf_removepointer.h:267
Definition bslmf_movableref.h:863
Definition bslmf_movableref.h:825
Definition bslmf_movableref.h:791
static BSLS_KEYWORD_CONSTEXPR const t_TYPE & forward(const t_TYPE &t) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_util.h:460