// bsls_exceptionutil.h -*-C++-*- #ifndef INCLUDED_BSLS_EXCEPTIONUTIL #define INCLUDED_BSLS_EXCEPTIONUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide simplified exception constructs for non-exception builds. // //@CLASSES: // //@MACROS: // BSLS_TRY: begin a 'try'-block // BSLS_CATCH(X): begin a 'catch'-block for exception 'X' // BSLS_THROW(X): 'throw' exception 'X' // BSLS_RETHROW: re-'throw' the current exception // BSLS_EXCEPTION_SPEC(SPEC): add 'SPEC' to function exception specification // BSLS_NOTHROW_SPEC: declare that a function throws no exceptions // BSLS_EXCEPTION_VIRTUAL_NOTHROW: virtual 'exception' method except. spec. // BSLS_EXCEPTION_WHAT_NOTHROW: 'exception::what()' except. spec. // //@SEE_ALSO: bsls_compilerfeatures, bsls_cpp11 // //@DESCRIPTION: Code that uses 'try', 'throw' and 'catch' constructs will // often fail to compile when exceptions are disabled using a compiler switch, // even if the 'throw' statement is unlikely to be executed at run-time or if // the 'catch' clause can safely ignore an exception that will never occur. // This component provides macros to replace 'try', 'throw' and 'catch'. // These macros expand to normal exception constructs when exceptions are // enabled and reasonable alternatives (usually no-ops) when exceptions are // disabled. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Using 'bsls_exceptionutil' to Implement 'vector' ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Suppose we wanted to define an implementation of a standard-defined 'vector' // template. Unfortunately, the C++ standard requires that 'vector' provide an // 'at' method that throws an 'out_of_range' exception if the supplied index is // not in the valid range of elements in the vector. In this example we show // using 'BSLS_THROW' so that such an implementation will compile in both // exception enabled and non-exception enabled builds. Note that apart from // memory allocation, and where required by the C++ standard, types defined in // the BDE libraries do not throw exceptions, and are typically // "exception-neutral" (see {'bsldoc_glossary'}), meaning they behave // reasonably in the presence of injected exceptions, but do not themselves // throw any exceptions. // // First we open a namespace 'myStd' and define an 'out_of_range' exception // that the 'at' method will throw (note that in practice, 'out_of_range' would // inherit from 'logic_error')': //.. // namespace myStd { // // class out_of_range // ... // { // // ... // }; //.. // Next, we declare the 'vector' template and its template parameters (note // that the majority of the implementation is elided, for clarity): //.. // template <class VALUE, class ALLOCATOR /* ... */> // class vector { // // DATA // VALUE *d_begin_p; // VALUE *d_end_p; // // ... // // public: // // typedef typename ALLOCATOR::size_type size_type; // // //... //.. // Then, we define the 'at' method, which is required to throw an // 'out_of_range' exception. //.. // const VALUE& at(size_type index) const // { // if (d_begin_p + index < d_end_p) { // return d_begin_p[index]; // RETURN // } //.. // Now, we use 'BSLS_THROW' to throw an 'out_of_range' exception: //.. // BSLS_THROW(out_of_range(/* ... */)); // } //.. // Finally, we complete the (mostly elided) 'vector' implementation: //.. // // ... // // }; // // } // close namespace myStd // // struct DummyAllocator { // typedef int size_type; // }; //.. // ///Example 2: Using 'bsls_exceptionutil' to Throw and Catch Exceptions ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // The following example demonstrates the macros defined in the // 'bsls_exceptionutil' component to both throw and catch exceptions in a way // that will allow the code to compile in non-exception enabled builds. // // First, we define a couple of example exception classes (note that we cannot // use 'bsl::exception' in this example, as this component is defined below //'bsl_exception.h'): //.. // class my_ExClass1 // { // }; // // class my_ExClass2 // { // }; //.. // Then, we define a function that never throws an exception, and use the // 'BSLS_NOTHROW_SPEC' to ensure the no-throw exception specification will be // present in exception enabled builds, and elided in non-exception enabled // builds: //.. // int noThrowFunc() BSLS_NOTHROW_SPEC // { // return -1; // } //.. // Next, we define a function that might throw 'my_ExClass1' or 'my_ExClass2', // and docuemnt which exception types might be thrown. Note that dynamic // exception specifications are deprecated in C++11 and removed from the // language in C++17, so should not be used as a substitute for documentation // in earlier language dialects: //.. // int mightThrowFunc(int i) // // Return the specified integer 'i', unless '1 == 1' or '2 == i'. If // // '1 == i' throw an exception of type 'my_ExcClass1'. If '2 == i' // // throw an exception of type 'my_ExcClass2'. Note that if exceptions // // are not enabled in the current build mode, then the program will // // 'abort' rather than throw. // { // switch (i) { // case 0: break; // case 1: BSLS_THROW(my_ExClass1()); // case 2: BSLS_THROW(my_ExClass2()); // } // return i; // } //.. // Then, we start the definition of a 'testMain' function: //.. // int testMain() // { //.. // Next, we use the 'BDE_BUILD_TARGET_EXC' exception build flag to determine, // at compile time, whether to initialize 'ITERATIONS' to 3 (for exception // enabled builds) or 1 (for non-exception enabled builds). The different // values of the 'ITERATOR' ensure the subsequent for-loop calls // 'mightThrowFunc' in a way that generates exceptions for only exception // enabled builds: //.. // #ifdef BDE_BUILD_TARGET_EXC // const int ITERATIONS = 3; // #else // const int ITERATIONS = 1; // #endif // // for (int i = 0; i < ITERATIONS; ++i) { //.. // Then, we use a pair of nested 'try' blocks constructed using // 'BSLS_TRY', so that the code will compile whether or not exceptions are // enabled (note that the curly brace placement is identical to normal // 'try' and 'catch' constructs): //.. // int caught = -1; // BSLS_TRY { // // BSLS_TRY { // noThrowFunc(); // mightThrowFunc(i); //.. // Notice that this example is careful to call 'mightThrowFunc' in such a way // that it will not throw in non-exception builds. Although the use of // 'BSLS_TRY', 'BSLS_THROW', and 'BSLS_CATCH' ensures the code *compiles* in // both exception, and non-exception enabled builds, attempting to 'BSLS_THROW' // an exception in a non-exception enabled build will invoke the assert handler // and will typically abort the task. //.. // caught = 0; // Got here if no throw // } //.. // Next, we use 'BSLS_CATCH' to define blocks for handling exceptions that may // have been thrown from the preceding 'BSLS_TRY': //.. // BSLS_CATCH(my_ExClass1) { // caught = 1; // } // BSLS_CATCH(...) { //.. // Here, within the catch-all handler, we use the 'BSLS_RETHROW' macro to // re-throw the exception to the outer 'try' block: //.. // BSLS_RETHROW; // } // end inner try-catch // } // BSLS_CATCH(my_ExClass2) { // caught = 2; // } // BSLS_CATCH(...) { // assert("Should not get here" && 0); // } // end outer try-catch // // if (0 != caught) { // if (verbose) // printf("Caught exception my_ExClass: %d\n", caught); // } // else { // if (verbose) // printf("Caught no exceptions: %d\n", caught); // } // assert(i == caught); // // } // end for (i) // // return 0; // } //.. #include <bsls_assert.h> #include <bsls_buildtarget.h> #include <bsls_compilerfeatures.h> #include <bsls_deprecate.h> #include <bsls_libraryfeatures.h> // ====== // macros // ====== #ifdef BDE_BUILD_TARGET_EXC // ------------------ // Exceptions enabled // ------------------ # define BSLS_TRY try // Start a try block. // Exceptions enabled: 'try' // Exceptions disabled: start of a normal (non-try) block # define BSLS_CATCH(X) catch (X) // Catch exception 'X'. 'X' must be a type with optional variable name // Exceptions enabled: 'catch (X)' // Exceptions disabled: ignore following block # define BSLS_THROW(X) throw X // Throw exception object 'X'. // Exceptions enabled: 'throw (X)' // Exceptions disabled: abort with a message # define BSLS_RETHROW throw // Within a 'BSLS_CATCH' clause, re-throw the last exception // Exceptions enabled: 'throw' // Exceptions disabled: abort with a message # if !BSLS_DEPRECATE_IS_ACTIVE(BDE, 3, 17) # if defined(BSLS_COMPILERFEATURES_SUPPORT_THROW_SPECIFICATIONS) # define BSLS_EXCEPTION_SPEC(SPEC) throw SPEC // DEPRECATED: This macro is deprecated, as the language feature itself // is deprecated in C++11, and is entirely removed in C++17. It is // recommended to simply document the potential set of exceptions that // may be thrown by a function instead. // // Declare a dynamic exception specification for a function. // Usage: //.. // void f() BSLS_EXCEPTION_SPEC((std::logic_error)); //.. // 'SPEC' must be a comma-separated list of one or more exception // types enclosed in parenthesis. (Double parenthesis are mandatory) // Use 'BSLS_NOTHROW_SPEC' (below) to declare that a function does not // throw. // Exceptions enabled: 'throw SPEC' // Exceptions disabled: empty # else # define BSLS_EXCEPTION_SPEC(SPEC) // DEPRECATED: This macro is deprecated, and cannot expand to a // supported syntax on the current platform. # endif // BSLS_COMPILERFEATURES_SUPPORT_THROW_SPECIFICATIONS # endif // BSLS_DEPRECATE_IS_ACTIVE # if defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) # define BSLS_NOTHROW_SPEC noexcept # else # define BSLS_NOTHROW_SPEC throw () # endif // Declare that a function does not throw any exceptions: // Usage: //.. // void f() BSLS_NOTHROW_SPEC; //.. // Exceptions enabled: 'throw ()' or 'noexcept' // Exceptions disabled: empty # define BSLS_EXCEPTION_VIRTUAL_NOTHROW BSLS_NOTHROW_SPEC // The exception specification that overrides of the virtual destructor // and the 'exception::what()' virtual method should use. It is a // separate macro from 'BSLS_NOTHROW_SPEC' because the GNU library // unconditionally declares the function 'throw()', regardless if // exceptions are enabled or not - and overrides must do the same. # define BSLS_EXCEPTION_WHAT_NOTHROW BSLS_EXCEPTION_VIRTUAL_NOTHROW // More specialized name for the no-throw declaration of the // 'exception::what()' method. Use 'BSLS_EXCEPTION_VIRTUAL_NOTHROW' // instead. #else // If exceptions are disabled // ------------------- // Exceptions disabled // ------------------- # define BSLS_TRY if (1) # define BSLS_CATCH(X) else if (0) # define BSLS_THROW(X) BSLS_ASSERT_INVOKE_NORETURN( \ "Tried to throw " #X \ " with exceptions disabled"); # define BSLS_RETHROW BSLS_ASSERT_INVOKE_NORETURN( \ "Tried to re-throw exception " \ "with exceptions disabled"); # if !BSLS_DEPRECATE_IS_ACTIVE(BDE, 3, 17) # define BSLS_EXCEPTION_SPEC(SPEC) # endif // BSLS_DEPRECATE_IS_ACTIVE # define BSLS_NOTHROW_SPEC # if defined(BSLS_LIBRARYFEATURES_STDCPP_GNU) || \ defined(BSLS_LIBRARYFEATURES_STDCPP_LIBCSTD) || \ defined(BSLS_LIBRARYFEATURES_STDCPP_IBM) # if defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) # define BSLS_EXCEPTION_VIRTUAL_NOTHROW noexcept # else # define BSLS_EXCEPTION_VIRTUAL_NOTHROW throw () # endif # else # define BSLS_EXCEPTION_VIRTUAL_NOTHROW # endif // The exception specification that overrides of the // 'exception::what()' virtual method should use. It is a separate // macro from 'BSLS_NOTHROW_SPEC' because the GNU library // unconditionally declares the function 'throw()', regardless if // exceptions are enabled or not - and overrides must do the same. #endif // BDE_BUILD_TARGET_EXC namespace BloombergLP { } // close enterprise namespace #endif // ! defined(INCLUDED_BSLS_EXCEPTIONUTIL) // ---------------------------------------------------------------------------- // Copyright 2013 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------