Re: How to make this exception-safe
On Nov 18, 1:43 pm, Triple-DES <DenPlettf...@gmail.com> 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()?
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.
There are a number of ways:
1. use a sentry class. Mine looks something like
template<class T>
struct DeleteObject{
void operator()(T v){
delete v;
}
};
//for maps use these...
template<class T>struct DeletePairSecond{
void operator()(T v){
delete v.second;
}
};
template<class T>struct DeletePairFirst{
void operator()(T v){
delete v.first;
}
};
template<class T>struct DeletePairBoth{
void operator()(T v){
delete v.first;
delete v.second;
}
};
template<class Container, class Delete=DeleteObject<typename
Container::value_type> >
struct PointerContainerSentry {
typedef Container container_type;
PointerContainerSentry(container_type&c):m_cont(c){}
~PointerContainerSentry(){
using std::for_each;
for_each(m_cont.begin(),m_cont.end(),Delete());
m_cont.clear();
}
private:
container_type & m_cont;
void operator=(PointerContainerSentry const&);
PointerContainerSentry(PointerContainerSentry const&);
};
Then modify struct V like
struct V{
V();
private:
std::vector<C*> _v;
PointerContainerSentry<std::vector<C*> > sentry;
V(const V&);//not really safe for containers of raw pointers
//in any case
};
V:V():sentry(_v) {
_v.reserve(3);
_v.push_back( new C(2) );
_v.push_back( new C(1) );
_v.push_back( new C(3) );
}
This has the added benefit of cleaning up _v in ~V automatically.
Lance
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]