Re: How to make this exception-safe
Triple-DES wrote:
Consider the following code:
#include <vector>
struct C {
explicit C(int) {} // may throw
private:
C(const C&);
C& operator=(const C&);
};
struct V {
V() {
// may leak if push_back or C::C(int) throws
v_.push_back( new C(2) );
v_.push_back( new C(1) );
v_.push_back( new C(3) );
}
~V() {} // delete all elems of v
private:
std::vector<C*> v_;
};
How would you go about making an exception-safe version of V::V()?
A general rule is that a newly acquired resource should immediately
be owned by an object of a class that manages the resource properly.
In this case, the result of new C(...) should immediately be owned
by a smart pointer, or a vector of pointers that manages the pointees.
This is what I could come up with:
// 1st attempt
#include <memory>
V::V() {
v_.reserve(3);
std::auto_ptr<C> c1( new C(2) );
std::auto_ptr<C> c2( new C(1) );
std::auto_ptr<C> c3( new C(3) );
v_.push_back( c1.release() );
v_.push_back( c2.release() );
v_.push_back( c3.release() );
}
Which is tedious if you are inserting more objects. Does anyone have a
better solution?
PS! boost/tr1 shared_ptr or similar can not be used.
The above attempt doesn't help you much, because after release(),
push_back() can still throw and the C object goes unmanaged.
One way is to keep the auto_ptr objects through the lifetime of V
(as data members) and not calling release(), so that the auto_ptr
objects manage the C objects. Another way is to use a vector-of-
pointers class that manages the objects pointed to by its elements.
Its push_back() function should, in particular, destroy the object
pointed to by the argument if expanding the internal buffer fails.
--
Seungbeom Kim
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]