Why does `myvector.push_back(autoPtr.release())` provide the strong exception safety guarantee?

356 Views Asked by At

EDIT: I should've mentioned, I was looking at the documentation for Boost's ptr_sequence_adapter and it claims that their adapter for template< class U > void push_back( ::std::auto_ptr<U> x ); is equivalent to doing vec.push_back(autoPtr.release()); and also provides the strong exception guarantee. And then I realized I was confusing their description of the effect of the implementation for what the implementation actually was, and so this question is semi-nonsensical. I'm just leaving it here for posterity.

To me, it seems the call to std::auto_ptr<t> would succeed, and then the call to std::vector<t*>::push_back could throw an exception, and the pointer would be leaked.

It seems like you'd have to do this instead:

vec.push_back(0); //Attempts to allocate space in vector, could throw bad_alloc
vec.back() = autoPtr.release(); //Provides nothrow
2

There are 2 best solutions below

4
On BEST ANSWER

This is specifically a feature of the Boost pointer containers library.

The base push_back member function is defined as:

void push_back( value_type x )  // strong               
{
    this->enforce_null_policy( x, "Null pointer in 'push_back()'" );

    auto_type ptr( x );           // notrow
    this->base().push_back( x );  // strong, commit
    ptr.release();                // nothrow
}

(from the ptr_sequence_adapter.hpp header)

So, the push_back function itself takes ownership of the pointer and if reallocation fails, it takes responsibility for deleting the pointer.

The push_back overload that takes an auto_ptr is defined in terms of the base push_back function:

template< class U >
void push_back( std::auto_ptr<U> x )
{
    push_back( x.release() );
}

The pointer is released before the call to the base push_back, which is okay because the base push_back function has a strong guarantee that it will delete the pointer if an exception is thrown.

7
On

Transferring an object out of an auto_ptr releases that auto_ptr's control of the object. It no longer gets the benefits of the auto_ptr. You would have to place the object in another smart pointer in order to become exception safe again, or a container object that gives exception safety guarantees (if there are any?).

Please note that std::auto_ptr cannot be used directly in STL containers. For example, std::vector<auto_ptr<int> > will break. You can have pointers to auto_ptrs, and store the auto_ptrs somewhere else, but auto_ptr copy semantics doesn't jive with STL containers, which rely on copying.