Exception-safety comes in two major flavours:
- If an exception happens, your program ends in a sane state. Which one is unspecified.
- If an exception happens, your program ends in the original state.
The main challenge for you will be to deal with assignment and copy constructors throwing. As the comments already note, you shouldn't use memcpy
because that fails to call copy constructors. Copying a std::string
should also copy the character buffer, for instance, and a vector of strings is a perfectly normal type which you should support.
So, let's look at your vector's copy constructor. It will need to copy every element of the source vector. And each individual copy can throw. What if one of the strings is so long that a copy throws std::bad_alloc
?
Now, exception safety means that you leave the program in a sane state, so no memory leaks. Your vector's copy ctor failed, so the dtor won't run. Who cleans up T* array
then? This must be done in your copy ctor.
When the copy fails, there won't be a new vector, so you get the second type of exception safety for free. ("strong exception safety"). But let's look at the assignment operator next, v2 = v1
. There's an old vector that you will overwrite. If you first do a .resize(0)
and then copy over all elements, you may encounter an exception halfway through the copy. Your original vector content is gone, and the new content is incomplete. Still, you haven't leaked any memory yet nor have you copied half an element.
To make the assignment safe, there's a simple trick: first copy the source vector to a temporary vector. If this fails, no problem (see above). We didn't touch the destination yet. But if the assignment succeeds, we swap the array*
pointers, size
and capacity
of the temporary and the destination vectors. Swapping pointers and swapping ints is safe (can't throw). Finally, we let the temporary vector go out of scope which destroys the old vector elements that are no longer needed.
So, by doing all the dangerous operations on temporaries, we ensure that any exception doesn't touch the original state.
You'll need to check all your methods to see if these problems can occur, but the pattern is usually similar. Don't leak array
if an element copy or element assignment throws, do propagate that exception to your caller.