BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bsls_exceptionutil

Macros

#define BSLS_TRY   if (1)
 
#define BSLS_CATCH(X)   else if (0)
 
#define BSLS_THROW(X)
 
#define BSLS_RETHROW
 
#define BSLS_EXCEPTION_SPEC(SPEC)
 
#define BSLS_NOTHROW_SPEC
 
#define BSLS_EXCEPTION_VIRTUAL_NOTHROW
 

Detailed Description

Outline

Purpose

Provide simplified exception constructs for non-exception builds.

Classes

Macros

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 @ref 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(/* ... */));
}
#define BSLS_THROW(X)
Definition bsls_exceptionutil.h:374

Finally, we complete the (mostly elided) vector implementation:

// ...
};
} // close namespace myStd
struct DummyAllocator {
typedef int size_type;
};

Example 2: Using @ref 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;
}
#define BSLS_NOTHROW_SPEC
Definition bsls_exceptionutil.h:386

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;
noThrowFunc();
mightThrowFunc(i);
#define BSLS_TRY
Definition bsls_exceptionutil.h:370

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(...) {
#define BSLS_CATCH(X)
Definition bsls_exceptionutil.h:372

Here, within the catch-all handler, we use the BSLS_RETHROW macro to re-throw the exception to the outer try block:

} // 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;
}
#define BSLS_RETHROW
Definition bsls_exceptionutil.h:378

Macro Definition Documentation

◆ BSLS_CATCH

#define BSLS_CATCH (   X)    else if (0)

◆ BSLS_EXCEPTION_SPEC

#define BSLS_EXCEPTION_SPEC (   SPEC)

◆ BSLS_EXCEPTION_VIRTUAL_NOTHROW

#define BSLS_EXCEPTION_VIRTUAL_NOTHROW

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.

◆ BSLS_NOTHROW_SPEC

#define BSLS_NOTHROW_SPEC

◆ BSLS_RETHROW

#define BSLS_RETHROW
Value:
"Tried to re-throw exception " \
"with exceptions disabled");
#define BSLS_ASSERT_INVOKE_NORETURN(X)
Definition bsls_assert.h:1895

◆ BSLS_THROW

#define BSLS_THROW (   X)
Value:
"Tried to throw " #X \
" with exceptions disabled");

◆ BSLS_TRY

#define BSLS_TRY   if (1)