// bslalg_autoarraydestructor.h -*-C++-*- #ifndef INCLUDED_BSLALG_AUTOARRAYDESTRUCTOR #define INCLUDED_BSLALG_AUTOARRAYDESTRUCTOR #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a proctor for destroying arrays. // //@CLASSES: // bslalg::AutoArrayDestructor: exception-neutrality proctor for arrays // //@SEE_ALSO: bslma_autodestructor // //@DESCRIPTION: This component provides a proctor object to manage a contiguous // (in-place) sequence of otherwise-unmanaged instances of a user-defined type. // If not explicitly released, all objects managed by the proctor object are // automatically destroyed by the proctor's destructor, using the // 'bslalg_arraydestructionprimitives'. // // In most instances, 'bslma::AutoDestructor' can also be used, but this // component is more useful in cases where it is simpler to think in terms of // two pointers at the ends of the array being managed, rather than an origin // and offset. // ///Usage ///----- // In this section we show intended use of this component. // ///Example 1: Managing an Array Under Construction ///- - - - - - - - - - - - - - - - - - - - - - - - // In most instances, the use of a 'bslalg::AutoArrayDestructor' could be // handled by a 'bslma::AutoDeallocator', but sometimes it is conceptually // clearer to frame the problem in terms of a pair of pointers rather than a // pointer and an offset. // // Suppose we have a class, 'UsageType' that allocates a block of memory upon // construction, and whose constructor takes a 'char'. Suppose we want to // create an array of elements of such objects in an exception-safe manner. // // First, we create the type 'UsageType': //.. // // =============== // // class UsageType // // =============== // // class UsageType { // // This test type contains a 'char' in some allocated storage. It has // // no traits other than using a 'bslma' allocator. // // char *d_data_p; // managed single char // bslma::Allocator *d_allocator_p; // allocator (held, not owned) // // public: // // CREATORS // explicit UsageType(char c, bslma::Allocator *basicAllocator = 0) // : d_data_p(0) // , d_allocator_p(bslma::Default::allocator(basicAllocator)) // { // d_data_p = (char *)d_allocator_p->allocate(sizeof(char)); // *d_data_p = c; // } // // ~UsageType() // { // *d_data_p = '_'; // d_allocator_p->deallocate(d_data_p); // d_data_p = 0; // } // // // ACCESSORS // char datum() const // { // return *d_data_p; // } // }; // // namespace BloombergLP { // namespace bslma { // // template <> // struct UsesBslmaAllocator<UsageType> : bsl::true_type {}; // // } // close package namespace // } // close enterprise namespace //.. // Then, in 'main', we create a 'TestAllocator' to supply memory (and to verify // that no memory is leaked): //.. // bslma::TestAllocator ta; //.. // Next, we create the pointer for our array: //.. // UsageType *array; //.. // Then, we declare a string of characters we will use to initialize the // 'UsageType' objects in our array. //.. // const char *DATA = "Hello"; // const size_t DATA_LEN = std::strlen(DATA); //.. // Next, we verify that even right after exceptions have been thrown and // caught, no memory is outstanding: //.. // assert(0 == ta.numBlocksInUse()); //.. // Then, we allocate our array and create a guard to free it if a subsequent // allocation throws an exception: //.. // array = (UsageType *) ta.allocate(DATA_LEN * sizeof(UsageType)); // bslma::DeallocatorProctor<bslma::Allocator> arrayProctor(array, &ta); //.. // Next, we establish an 'AutoArrayDestructor' on 'array' to destroy any valid // elements in 'array' if an exception is thrown: //.. // bslalg::AutoArrayDestructor<UsageType,> arrayElementProctor(array, array); //.. // Notice that we pass 'arrayElementProctor' pointers to the beginning and end // of the range to be guarded (we start with an empty range since no elements // have been constructed yet). // // Then, we iterate through the valid chars in 'DATA' and use them to construct // the elements of the array: //.. // UsageType *resultElement = array; // for (const char *nextChar = DATA; *nextChar; ++nextChar) { //.. // Next, construct the next element of 'array': //.. // new (resultElement++) UsageType(*nextChar, &ta); //.. // Now, move the end of 'arrayElementProctor' to cover the most recently // constructed element: //.. // arrayElementProctor.moveEnd(1); // } //.. // At this point, we have successfully created our array. // // Then, release the guards so they won't destroy our work when they go out of // scope: //.. // arrayProctor.release(); // arrayElementProctor.release(); //.. // Next, exit the exception testing block: // // Then, verify that the array we have created is as expected: //.. // assert('H' == array[0].datum()); // assert('e' == array[1].datum()); // assert('l' == array[2].datum()); // assert('l' == array[3].datum()); // assert('o' == array[4].datum()); //.. // Finally, destroy & free our work and verify that no memory is leaked: //.. // for (size_t i = 0; i < DATA_LEN; ++i) { // array[i].~UsageType(); // } // ta.deallocate(array); // // assert(0 == ta.numBlocksInUse()); //.. #include <bslscm_version.h> #include <bslalg_arraydestructionprimitives.h> #include <bslma_stdallocator.h> #include <bsls_assert.h> #include <cstddef> // size_t namespace BloombergLP { namespace bslalg { // ========================= // class AutoArrayDestructor // ========================= template <class OBJECT_TYPE, class ALLOCATOR = bsl::allocator<OBJECT_TYPE> > class AutoArrayDestructor { // This 'class' provides a specialized proctor object that, upon // destruction and unless the 'release' method has been called, destroys // the elements in a segment of an array of parameterized type // 'OBJECT_TYPE'. The elements destroyed are delimited by the "guarded" // range '[ begin(), end() )'. // DATA OBJECT_TYPE *d_begin_p; // address of first element in guarded range OBJECT_TYPE *d_end_p; // first address beyond last element in guarded // range ALLOCATOR d_allocator; // allocator private: // NOT IMPLEMENTED AutoArrayDestructor(const AutoArrayDestructor&); AutoArrayDestructor& operator=(const AutoArrayDestructor&); public: // TYPES typedef std::ptrdiff_t difference_type; // CREATORS AutoArrayDestructor(OBJECT_TYPE *begin, OBJECT_TYPE *end, ALLOCATOR allocator = ALLOCATOR()); // Create an array exception guard object for the sequence of elements // of the parameterized 'OBJECT_TYPE' delimited by the range specified // by '[ begin, end )'. The behavior is undefined unless // 'begin <= end' and each element in the range '[ begin, end )' has // been initialized. ~AutoArrayDestructor(); // Call the destructor on each of the elements of the parameterized // 'OBJECT_TYPE' delimited by the range '[ begin(), end() )' and // destroy this array exception guard. // MANIPULATORS OBJECT_TYPE *moveBegin(difference_type offset = -1); // Move the begin pointer by the specified 'offset', and return the new // begin pointer. OBJECT_TYPE *moveEnd(difference_type offset = 1); // Move the end pointer by the specified 'offset', and return the new // end pointer. void release(); // Set the range of elements guarded by this object to be empty. Note // that 'begin() == end()' following this operation, but the specific // value is unspecified. }; // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ // ------------------------- // class AutoArrayDestructor // ------------------------- // CREATORS template <class OBJECT_TYPE, class ALLOCATOR> inline AutoArrayDestructor<OBJECT_TYPE, ALLOCATOR>::AutoArrayDestructor( OBJECT_TYPE *begin, OBJECT_TYPE *end, ALLOCATOR allocator) : d_begin_p(begin) , d_end_p(end) , d_allocator(allocator) { BSLS_ASSERT_SAFE(!begin == !end); BSLS_ASSERT_SAFE(begin <= end); } template <class OBJECT_TYPE, class ALLOCATOR> inline AutoArrayDestructor<OBJECT_TYPE, ALLOCATOR>::~AutoArrayDestructor() { BSLS_ASSERT_SAFE(!d_begin_p == !d_end_p); BSLS_ASSERT_SAFE(d_begin_p <= d_end_p); ArrayDestructionPrimitives::destroy(d_begin_p, d_end_p, d_allocator); } // MANIPULATORS template <class OBJECT_TYPE, class ALLOCATOR> inline OBJECT_TYPE *AutoArrayDestructor<OBJECT_TYPE, ALLOCATOR>::moveBegin( difference_type offset) { BSLS_ASSERT_SAFE(d_begin_p || 0 == offset); BSLS_ASSERT_SAFE(d_end_p - d_begin_p >= offset); d_begin_p += offset; return d_begin_p; } template <class OBJECT_TYPE, class ALLOCATOR> inline OBJECT_TYPE * AutoArrayDestructor<OBJECT_TYPE, ALLOCATOR>::moveEnd(difference_type offset) { BSLS_ASSERT_SAFE(d_end_p || 0 == offset); BSLS_ASSERT_SAFE(d_end_p - d_begin_p >= -offset); d_end_p += offset; return d_end_p; } template <class OBJECT_TYPE, class ALLOCATOR> inline void AutoArrayDestructor<OBJECT_TYPE, ALLOCATOR>::release() { d_begin_p = d_end_p; } } // close package namespace #ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY // ============================================================================ // BACKWARD COMPATIBILITY // ============================================================================ #ifdef bslalg_AutoArrayDestructor #undef bslalg_AutoArrayDestructor #endif #define bslalg_AutoArrayDestructor bslalg::AutoArrayDestructor // This alias is defined for backward compatibility. #endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY } // 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 ----------------------------------