// bslma_exceptionguard.h -*-C++-*- #ifndef INCLUDED_BSLMA_EXCEPTIONGUARD #define INCLUDED_BSLMA_EXCEPTIONGUARD #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a check that objects throwing exceptions do not change. // //@CLASSES: // bslma::ExceptionGuard: guard to check an object state has not changed // //@SEE_ALSO: bslma_testallocator // //@DESCRIPTION: This component provides a class, 'bslma::ExceptionGuard', that // can be used to ASSERT if an object changes state when a method fails by // throwing an exception. This is often used to validate the strong exception // safety guarantee in a test driver, usually with the test support macros // provided by the component 'bslma_testallocator', such as // 'BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN'. The object under test must be // CopyConstructible, and support the extended copy constructor taking an // allocator. Note that this may be a generalised STL allocator, conforming to // the Allocator requirements of the C++ standard, rather than just a // 'bslma::Allocator'. This allows for testing standard library components // such as those in 'bsl'. // // As the constructor must make a copy of the object under test, this class // should not be used in a test driver until after the extended copy // constructor has been proven tested. Similarly, the destructor asserts that // the value has not changed using 'operator==', which should also be confirmed // as correct before relying on this class in a test driver. Finally, the // 'resetvalue' method should not be used prior to validating the copy- // assignment operator. // ///Usage ///----- // TBD ... #include <bslscm_version.h> #include <bsls_assert.h> namespace BloombergLP { namespace bslma { class Allocator; // ==================== // class ExceptionGuard // ==================== template <class OBJECT> class ExceptionGuard { // This class provide a mechanism to verify the strong exception guarantee // in exception-throwing code. On construction, this class stores the a // copy of an object of the parameterized type 'OBJECT' and the address of // that object. On destruction, if 'release' was not invoked, it will // verify the value of the object is the same as the value of the copy // create on construction. This class requires the copy constructor and // 'operator ==' to be tested before use. // DATA int d_line; // the line number at construction OBJECT d_copy; // copy of the object being tested const OBJECT *d_object_p; // address of the original object public: // CREATORS ExceptionGuard(const OBJECT *object, int line, Allocator *basicAllocator = 0); // Create the exception guard for the specified 'object' at the // specified 'line' number. Optionally, specify 'basicAllocator' used // to supply memory. template <class ALLOCATOR> ExceptionGuard(const OBJECT *object, int line, const ALLOCATOR& basicAllocator); // Create the exception guard for the specified 'object' at the // specified 'line' number. Optionally, specify 'basicAllocator' used // to supply memory. ~ExceptionGuard(); // Destroy the exception guard. If the guard was not released, verify // that the state of the object supplied at construction has not // change. // MANIPULATORS void release(); // Release the guard from verifying the state of the object. void resetValue(const OBJECT& value, int line); // Reset the expected state of the guarded object, if an exception // should propagate past this guard, to the specified 'value', which is // set from the specified 'line'. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // -------------------- // class ExceptionGuard // -------------------- // CREATORS template <class OBJECT> inline ExceptionGuard<OBJECT>::ExceptionGuard(const OBJECT *object, int line, Allocator *basicAllocator) : d_line(line) , d_copy(*object, basicAllocator) , d_object_p(object) { } template <class OBJECT> template <class ALLOCATOR> inline ExceptionGuard<OBJECT>::ExceptionGuard(const OBJECT *object, int line, const ALLOCATOR& basicAllocator) : d_line(line) , d_copy(*object, basicAllocator) , d_object_p(object) { } template <class OBJECT> ExceptionGuard<OBJECT>::~ExceptionGuard() { if (d_object_p) { // This test is tricky, as it is typically triggered while an exception // is active, and so should not have an assert handler that in turn // throws an exception. Note that as this assertion is the whole // purpose of the class, we use 'BSLS_ASSERT_OPT' so that it is active // in most build modes. BSLS_ASSERT_OPT(d_copy == *d_object_p); } } // MANIPULATORS template <class OBJECT> inline void ExceptionGuard<OBJECT>::release() { d_object_p = 0; } template <class OBJECT> inline void ExceptionGuard<OBJECT>::resetValue(const OBJECT& value, int line) { d_copy = value; d_line = line; } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // 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 ----------------------------------