Exception safety in the STL

J

John Harrison

Where can I find information on exception safety in the STL? I.e. which
methods on which types offer what level of exception safety.

Josuttis has a useful list of classes and methods but he fails to mention
common operations such as copy construction and assignment. I can't find any
mention of this in my copy of the standard at all, although according to
Josuttis exception safety guarantees are part of the standard.

A specific question, I've looked at the gcc 3.2 and the VC++.NET
implementation of list<T>::eek:perator= and neither appears to be exception
safe. That is if an excpetion is thrown you could end up with a partially
copied list. This surprises me, but is it OK according to the standard?

john
 
H

Howard Hinnant

| A specific question, I've looked at the gcc 3.2 and the VC++.NET
| implementation of list<T>::eek:perator= and neither appears to be exception
| safe. That is if an excpetion is thrown you could end up with a partially
| copied list. This surprises me, but is it OK according to the standard?

Yes, it is OK according to the standard. This is commonly called the
basic guarantee. In such a situation you are guaranteed that if an
exception is thrown, the list will remain in a self-consistent state.
No list invariants will be violated. No memory will be leaked.

In general, where the standard is silent, it is implying basic
exception safety.

It sounds like you are looking for strong exception safety: If an
exception is thrown, the list will be left in the same state as it was
before the operation began. This is also known as commit or rollback
semantics.

In general list::eek:perator= does not have the strong guarantee. But
some implementations may offer exceptions to this standard defined
behavior in certain circumstances. For example, the Metrowerks
std::list<T>::eek:perator= offers the strong guarantee if T::eek:perator= is
guaranteed not to throw. And this is accomplished with no additional
expense of memory.

If you have a std::container and you need to assign it with the strong
guarantee, you can always do so at the expense of using more memory:

template <class C>
inline
C&
strong_assign(C& x, const C& y)
{
C(y).swap(x);
return x;
}

Make a local copy of the source, and then swap that with the target.
The copy may throw, since this is allocating memory, and calling
C::value_type's copy constructor. If it does throw, the tempory
container will clean up after itself. If it does not throw, then it
is swapped into the target which is a no-throw operation.

The strong assign is not "better" than the basic assign. It is simply
different. Sometimes you need the basic, sometimes you need the
strong. The basic assign will in general use less memory and thus be
faster.
 
J

John Harrison

Howard Hinnant said:
| A specific question, I've looked at the gcc 3.2 and the VC++.NET
| implementation of list<T>::eek:perator= and neither appears to be exception
| safe. That is if an excpetion is thrown you could end up with a partially
| copied list. This surprises me, but is it OK according to the standard?

Yes, it is OK according to the standard. This is commonly called the
basic guarantee. In such a situation you are guaranteed that if an
exception is thrown, the list will remain in a self-consistent state.
No list invariants will be violated. No memory will be leaked.

That surprises me because (according to Josuttis at least) list offers
strong exception safety on most other operations (insert for instance). I
guess this is so to avoid having to allocate extra memory.
In general, where the standard is silent, it is implying basic
exception safety.

I still haven't been able to find the part of the standard that deals with
this. Could you point out where it is?
It sounds like you are looking for strong exception safety: If an
exception is thrown, the list will be left in the same state as it was
before the operation began. This is also known as commit or rollback
semantics.

In general list::eek:perator= does not have the strong guarantee. But
some implementations may offer exceptions to this standard defined
behavior in certain circumstances. For example, the Metrowerks
std::list<T>::eek:perator= offers the strong guarantee if T::eek:perator= is
guaranteed not to throw. And this is accomplished with no additional
expense of memory.

OK thanks, I'll take a look at the code.
If you have a std::container and you need to assign it with the strong
guarantee, you can always do so at the expense of using more memory:

template <class C>
inline
C&
strong_assign(C& x, const C& y)
{
C(y).swap(x);
return x;
}

Make a local copy of the source, and then swap that with the target.
The copy may throw, since this is allocating memory, and calling
C::value_type's copy constructor. If it does throw, the tempory
container will clean up after itself. If it does not throw, then it
is swapped into the target which is a no-throw operation.

The strong assign is not "better" than the basic assign. It is simply
different. Sometimes you need the basic, sometimes you need the
strong. The basic assign will in general use less memory and thus be
faster.

john
 
D

Dhruv

On Sun, 06 Jul 2003 08:56:07 +0100, John Harrison wrote:

Even I am having a lot of trouble with the STL exception safety. I'd like
to know a thing. Suppose, I have a type whose destructor might throw. And
I make a list of that type. So, that would mean that even the dtor of the
list can throw. Am I correct?

To John: You can find a good tabular form of what you are looking for in
TC++PL, Special Edition, Pg 956. Basically, the Appendix E deals with
exception safety.

I kind of take it as a rule of thumb that dtors should not throw.
Now, here, it is mentioned that clear() has a nothrow guarantee, but
~list() has no such guarantee? What to infer from this? Should I assume
that since ~list() does verry little apart from calling clear(), it has
the same exception specifications as clear().


Regards,
-Dhruv.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top