C++ - Why does this have a strong exception guarantee?

Viewed 372

In The C++ Programming Language (4th edition), Stroustrup shows the following snippet when discussing exceptions (corrected version taken from this errata):

template<typename T, typename A>
void vector<T,A>::reserve(size_type newalloc)   // flawed first attempt
{
    if (newalloc<=capacity()) return;           // never decrease allocation
    vector<T,A> v(newalloc);                    // make a vector with the new size
    copy(vb.elem,vb.elem+size(),v.begin());     // copy elements
    vb.space = size();
    swap(*this,v);                          // install new value 
} // implicitly release old value

He also says that "this has the nice property of providing the strong guarantee". However, a couple of pages before he mentioned that std::copy doesn't provide a strong exception guarantee. Is this a mistake, or am I missing something?

2 Answers

As François pointed out, std::copy is changing v, which isn't a member of this. Therefore, if it fails, this is unaltered.

A strong exception guarantee can be achieved for a function even if some operations it performs don't provide that guarantee.

copy(vb.elem,vb.elem+size(),v.begin());

Although copy() does not provide a strong guarantee, it only modifies elements of v but leaves v in state in which it can be safely destroyed (i.e. its constructor can clean up). This is a weaker guarantee. However, if an exception is thrown, v and all objects is has allocated will be destroyed by vectors destructor before control returns to the caller of reserve(), and the net effect is as if they never existed. For the caller of reserve() that gives a strong guarantee.

All of the other operations in the function give either a strong guarantee or (since C++11) a nothrow guarantee. Before C++11, size() and capacity() did not provide a nothrow guarantee, but are both const methods that were easily implemented as nonthrowing - part of the case for making them nothrow in C++11. std::swap() has always been specified as nonthrowing, and was qualified nothrow in C++11.

Related