Re: Should the shared_ptr have release method?
Thiago Adams wrote:
In the boost site there is an FAQ answering why the shared_ptr
doesn't have the release method.
http://www.boost.org/libs/smart_ptr/shared_ptr.htm#FAQ
In general I think that the shared_ptr is not a tool just to
"share" pointers, but it is very useful to simplify the
implementations of exceptions safe functions.
The Motivation for "release()" method.
I want to return a vector of pointers of the type "Item". The
object "Item" can throw exceptions in constructor and I am trying to
create an exception safe function.
There are many ways to implement it, but actually I didn't find an
elegant way to do this.
The simple way is using two vectors of shared_ptr.
void (vector< shared_ptr<Item> > &vec)
{
vector< shared_ptr <Item> > local;
for (int i = 0; i < N, i++)
{
local.push_back(shared_ptr<Item> (new Item(i) ) );
}
local.swap(vec);
}
However, I think I should not penalize the caller to use a vector of
shared_ptrs, because the caller doesn't share pointers with anyone
else, and the simple RAII is enough. In top of that, sometimes the
caller needs to use Item * instead a vector<Item*> because it was
transferring data using C api. (For instance transferring buffers using
&vec[0])
So, what I need is to implement a function to swap between vector<
shared_ptr<Item> and vector< Item * >.
To create this function I need to remove ownership of shared_ptrs and
transfer to vector< Item * >. It is impossible because the shared_ptr
doesn't have release.
The questions are:
Should the shared_ptr have release method that works only if
use_count() == 1, and throws if use_count() > 1 ?
Am I using the wrong approach? There is a different smart pointer for
this?
Should we create a custom container to deal with this kind o problem?
If multiple shared_ptrs are sharing ownership of the same object, and
one of them calls release, what happens to all of the others? I can't
think of any answer to this question that makes any sense, and I
suspect that those who designed shared_ptr couldn't either, which is
why shared_ptr doesn't have a release method.
I would probably solve your problem by wrapping your loop in a
try/catch block. If any exceptions are thrown, iterate through the
vector deleting the existing items, then rethrow the exception. If you
are looking for a purely stack based approach (I find there is a
certain satisfaction to be had by achieving exception safety without
using try/catch), then you might try a helper template like the
following:
template <class T>
class ptr_vector_builder
{
private:
std::vector<T *> m_v ;
// No copies allowed.
ptr_vector_builder(const ptr_vector_builder &) ;
ptr_vector_builder & operator=(const ptr_vector_builder &) ;
public:
ptr_vector_builder()
{}
~ptr_vector_builder()
{
typedef typename std::vector<T *>::iterator iterator ;
for (iterator i = m_v.begin(); i != m_v.end(); ++i)
delete *i ;
}
void push_back(T * p)
{
std::auto_ptr<T> ap(p) ;
m_v.push_back(ap.get()) ;
ap.release() ;
}
void swap(std::vector<T *> & rhs)
{
m_v.swap(rhs) ;
}
} ;
Then your function becomes:
void f(std::vector<Item *> & vec)
{
ptr_vector_builder<Item> local ;
for (int i = 0; i < 10; ++i)
local.push_back(new Item(i)) ;
local.swap(vec) ;
}
--
Alan Johnson
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]