Are the following constructor and destructor exceptions safe and exception neutral?
template <class T>
class Stack {
public:
Stack();
~Stack();
private:
T *v_; // ptr to a memory area big
size_t vsize_; // enough for 'vsize_' T's
size_t vused_; // # of T's actually in use
};
template<class T>
Stack<T>::Stack()
: v_(new T[10]), // default allocation
vsize_(10),
vused_(0) // nothing used yet
{}
template <class T>
Stack<T>::~Stack() {
delete[] v_; // this can't throw
}
Let's define exception safety and exception neutrality.
Stack objects should always be in a correct and consistent state, regardless of any exceptions that might be thrown in the course of executing Stack's member functions.
If any exceptions are thrown, they should be propagated seamlessly through to the caller, who can deal with them as he pleases, because he knows the context of T
and we don't.
The standard requires that when an exception occurs and does not get handled, it gets propagated up to the call stack until it reaches a point that can handle it or until the program terminates.
new
call throw?With the new
keyword, if an exception occurs in the constructor, C++ automatically deallocates the memory allocated with the new
and releases it back to the system. Even if the object is partially constructed. So whether the new
operator succeeds or fails, the Stack
object will be in a consistent state.
But what about the vsize_
which is set to 10? It is also consistent because even if vsize_
is set, no memory was allocated, so the value of vsize_
does not matter.
Basically, if an object’s constructor exits due to an exception, the object is considered to have never existed (its lifetime never started) and any memory that was briefly or partially allocated is automatically destroyed by C++.
delete[]
call throw?The standard also requires the delete[]
operator to have a specific signature that does not allow it to throw exceptions.
void operator delete[]( void* ) throw();
void operator delete[]( void*, size_t ) throw();
These signatures indicate that the delete[]
operator must not throw exceptions during memory deallocation.
A safer and modern C++ way of preventing a function from throwing is the use of noexcept
keyword.