Vous êtes sur la page 1sur 25

Exception Handling in Depth

Monica Ciocan
May 14, 2012
Summary

● What are exceptions and what exception


handling means?
● A few words about exception specifications
and stack unwinding
● What is exception safety?
● Exception safety guarantees
● Example of an exception safe class design

May 14, 2012 Exception Handling in Depth 2


„Error handling is a difficult task for which the
programmer needs all the help that can be
provided.“
-Bjarne Stroustrup

„There are two ways to write error-free programs;


Only the third one works.“
-Alan Perlis

May 14, 2012 Exception Handling in Depth 3


Exceptions and Exception Handling
Exceptions are run-time anomalies that occur
during the execution of a program.
Exception Handling
- responsible of raising and handling exceptions
- allows independent parts of a program to
communicate about and handle problems that
arise during the execution of that program
- it relies on the problem-detecting part throwing
an object to the handler
May 14, 2012 Exception Handling in Depth 4
What is Exception Handling good for?

Robustness:
● helps to easily trace the error
● terminate the program if it cannot handle the
problem

May 14, 2012 Exception Handling in Depth 5


Exception specifications

● are used to indicate what exception types can be thrown out


of a function
● Hint: avoid exception specifications! (when violated, by default
they immediately terminate your program and they don't
prevent from throwing exceptions not listed in the
specification)

void f(int i) ; //all exceptions allowed


void f(int i) throw(type); //can throw an
//exception of type type
void f(int i) throw(); //no exceptions allowed
May 14, 2012 Exception Handling in Depth 6
May 14, 2012 Exception Handling in Depth 7
What is exception safety?

An operation on an object is said to be exception safe if that


operation leaves the object in a valid state when the operation is
terminated by throwing an exception.
The basic tools available for writing exception-safe code are
(1) the try-block, and
(2) the support for the ‘‘resource acquisition is initialization’’(RAII)
technique.

May 14, 2012 Exception Handling in Depth 8


The Guarantees

1. Basic Guarantee: no leaks occur, and affected


objects are still destructible and usable in a
consistent(but not necessarly predictable) state.
2. Strong Guarantee: if an operation terminates
because of an exception, program state will remain
unchanged.
3. No-throw Guarantee: the operation will not throw an
exception under any circumstances.

May 14, 2012 Exception Handling in Depth 9


Exception safe class design
Consider the following Stack class

template<typename T> class Stack


{
public:
Stack();
~Stack();
Stack(const Stack&);
Stack& operator=(const Stack&);
size_t Count() const;
void Push(const T&);
T Pop();

private:
T* v_; //ptr to a memory area big
size_t vsize_; // enough for 'vsize_' T's
size_t vused_; // nr of T's actually in use
};

May 14, 2012 Exception Handling in Depth 10


Exception safe class design

Implementation of the default Implementation of the


constructor. This is exception destructor. This is this
safe and exception neutral. exception safe.

template<typename T>Stack<T>::Stack() template<typename T>Stack<T>::~Stack()


:v_(new T[10]), {
vsize_(10), delete[] v_; //this can't throw
vused_(0) }
{
}

May 14, 2012 Exception Handling in Depth 11


Exception safe class design
Helper function (to manage allocating and growing memory) for
copy construction and copy assignment.
template<typename T>T* NewCopy(const T* src, size_t srcsize, size_t destsize)
{ assert(destsize >= srcsize);
T* dest = new T[destsize];
try {
copy(src, src+srcsize, dest); }
catch(...)
{ delete[] dest; //this can't throw;
throw(); //rethrow original exception
}
return dest;
}
May 14, 2012 Exception Handling in Depth 12
Exception safe class design
Implementation of the copy assignment. Is this exception safe?
template<typename T>Stack<T>& Stack<T>::operator =(const Stack<T>& other)
{
if( this!= other)
{
T* v_new = NewCopy(other.v_, other.vsize_, other.vsize_);
delete[] v_; //this can't throw;
v_ = v_new; //take ownership;
vsize_ = other.vsize_;
vused_ = other.vused_;
}
return *this; //safe, no copy involved
}

May 14, 2012 Exception Handling in Depth 13


Exception safe class design
Implementation of the copy assignment. Is this exception safe?
template<typename T>Stack<T>& Stack<T>::operator =(const Stack<T>& other)
{
if( this!= other)
{
T* v_new = NewCopy(other.v_, other.vsize_, other.vsize_);
delete[] v_; //this can't throw;
v_ = v_new; //take ownership;
vsize_ = other.vsize_;
vused_ = other.vused_;
}
return *this; //safe, no copy involved
}

Yes, with the help of the NewCopy function.

May 14, 2012 Exception Handling in Depth 14


Exception safe class design
Another way of obtaining a strong exception–safe copy
assignment would be:
● provide a non-throwing Swap() function that swap the internal
state of two objects:
void T::Swap(T& another) throw()
{ //...swap the guts of *this and other.. }
● implement operator=() using the „create a temporary and
swap“ idiom:
Stack& operator=(const Stack& other)
{ Stack temp(other); //do all the work off to the side
Swap(temp); //then „commit“ the work using
return *this; //nonthrowing operations only
}
May 14, 2012 Exception Handling in Depth 15
Exception safe class design
Implementation of the Push function. This is this exception safe.
template<typename T>void Stack<T>::Push(const T& t)
{ if(vused_ == vsize_) //grow if necessary
{ size_t vsize_new = vsize_*2 +1;
T* v_new = NewCopy(v_, vsize_, vsize_new);
delete[] v_; //this can't throw;
v_ = v_new; //take ownership;
vsize_ = vsize_new;
}
v_[vused_] = t;
++vused_;
}

May 14, 2012 Exception Handling in Depth 16


Exception safe class design
Implementaion of the Pop function. Is this exception safe?
template<typename T>T Stack<T>::Pop()
{
if(vused_ == 0)
throw std::runtime_error("pop from empty stack");
else
{
T result = v_[vused_ - 1];
--vused_;
return result;
}
}

May 14, 2012 Exception Handling in Depth 17


Exception safe class design
Implementaion of the Pop function. Is this exception safe?
template<typename T>T Stack<T>::Pop()
{
if(vused_ == 0)
throw std::runtime_error("pop from empty stack");
else
{
T result = v_[vused_ - 1];
--vused_;
return result;
}
}

No!!! Objects may get lost in case of exceptions!

May 14, 2012 Exception Handling in Depth 18


Exception safe class design

The real problem: Pop has to responsabilities:


- to pop the top-most element
- to return the just popped value

Guideline: Prefer cohesion. Always endeavor to give each piece


of code – each module, each class, each function – a single, well
defined responsability.

May 14, 2012 Exception Handling in Depth 19


Exception safe class design (solution I)
Solution: separate the two responsabilities for making a function
for each.
template<typename T>T& Stack<T>::Top()
{ if(vused_ == 0)
throw std::runtime_error("pop from empty stack");
return v_[vused_ -1];
}
template<typename T>void Stack<T>::Pop()
{ if(vused_ == 0)
throw std::runtime_error("pop from empty stack");
else
--vused_;
}
May 14, 2012 Exception Handling in Depth 20
Exception safe class design (solution II)

Another way of implementing Stack exception-safe is by using a


better encapsulation technique.
In our example we encapsulate the memory management work,
introducing a helper class, StackImpl .

In C++, Is-Implemented-In-Terms-Of can be expressed by either


nonpublic inheritance or by containment/delegation.
When writting a class T that is implemented in terms of a class
U , the two main options are to inherit privately from U or to
contain a U member object.

1. Private Base Class – when the acces specifier is protected.


2. Private Member - when the acces specifier is public.
May 14, 2012 Exception Handling in Depth 21
template<class T> class StackImpl
{
public: // protected
StackImpl(size_t size=0);
~StackImpl();
void Swap(StackImpl& other) throw();
T* v_; //ptr to a memory area big
size_t vsize_; // enough for 'vsize_' T's
size_t vused_; // nr of T's actually in use
private:
//private and undefined, no copying allowed
StackImpl(const StackImpl&);
StackImpl& operator=(const StackImpl&);
};

May 14, 2012 Exception Handling in Depth 22


Some Guidelines


Ensure that the errors always leave your program in a valid
state(basic guarantee).

Remember: error unsafe and „poor design“ go hand in hand.

Prefer cohesion – always eandeavor to give each piece of
code a single well defined responsability.

Avoid exception specifications.

In each function, take all the code that might emit an error and
do all that work safetly off to the side. Only when this work
succeeded, should you modify the program state using only
non-throwing operations.
May 14, 2012 Exception Handling in Depth 23
Summary

● What are exceptions and what exception


handling means?
● A few words about exception specifications
and stack unwinding
● What is exception safety?
● Exception safety guarantees
● Example of an exception safe class design

May 14, 2012 Exception Handling in Depth 24


References:
Exceptional C++, H.Sutter
C++ Coding Standards, H.Sutter, A. Alexandrescu
More Exceptional C++, H.Sutter
Change the Way You Write Exception-Safe Code – Forever,
A.Alexandrescu
Exception Safety: Concepts and Techniques, Bjarne Stroustrup
http://www.gotw.ca

May 14, 2012 Exception Handling in Depth 25

Vous aimerez peut-être aussi