Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Should the shared_ptr have release method?

2 views
Skip to first unread message

Thiago Adams

unread,
Jan 2, 2007, 1:50:45 PM1/2/07
to

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?


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Lance Diduck

unread,
Jan 3, 2007, 8:43:46 AM1/3/07
to
Perhaps in this case, one might just do it the old fashioned way:
template <class T>
struct delete_all(){
T* m_val;
delete_all(T &_a):m_val(&_a){}
~delete_all(){
if( m_val){
for (T::iterator i=m_val->begin();i!=m_val->end();++i)
delete *i;
m_val->clear();
}
}
void ignore(){m_val=0;}
};

void load(vector<Item*> & vec){
vector<Item*> loc_vec;
delete_all <vector<Item*> > d(loc_vec);
for (int i=0;i!=N;++i) loc_vec.push_back(new Item);
//now we are in "no-fail- area
{
delete_all<vector<Item*> >(vec);
//get rid of existing values, if any
}

vec.swap(loc_vec);
d.ignore();
}
Not exactly easy to write correctly, and this is a reason that
shared_ptr does not have release.

t.le...@rtsgroup.net

unread,
Jan 3, 2007, 9:23:59 AM1/3/07
to
Hi,

for me it looks like you're mixing motivations:
1) you wanna have a exception save function
2) you wanna have a container of items without shared pointers

> 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.

I don't see any relation to your aim. If the items c'tor throws an
exception you've to catch it otherwise your function couldn't be
exception safe for the user of this function.

May be you should consider implementing an initialization method to be
called for each newly created item to analyse the return value (error
code, simple: true/false). The item should not throw an exception
anymore then.

> 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 * >.

If you need - for any reason - a container of type
std::container<Item*> then see the example: (I'm using 'int' for
'Item')
- you've to make a copy of the items from the container of shared
items, if/when you're NOT sure about the life time of the two
containers. If both containers does have the same life time you just
need to copy the pointers ('csi[ix].get()' instead of 'new
int(*csi[ix])').
- of course you're responsible for deletion (when copied)

btw:
If someone decides to use a container with shared_ptr it's 100% not
good to remove ownership!

- - - example - - -
int main()
{
typedef vector<shared_ptr<int> > CSI;
typedef vector<int*> CI;

CSI csi;
CI ci;
int ix;

// init
for (ix = 0; ix < 10; ++ix)
csi.push_back(new int(ix));
// output
for (ix = 0; ix < 10; ++ix)
std::cout << *csi[ix] << std::endl;
// copy contents
for (ix = 0; ix < 10; ++ix)
ci.push_back(new int(*csi[ix]));
// output
for (ix = 0; ix < 10; ++ix)
std::cout << *ci[ix] << std::endl;
// cleanup
for (ix = 0; ix < 10; ++ix)
delete ci[ix];
return 0;

Alan Johnson

unread,
Jan 3, 2007, 9:20:58 AM1/3/07
to


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

Thiago Adams

unread,
Jan 3, 2007, 2:34:24 PM1/3/07
to

>>If multiple shared_ptrs are sharing ownership of the same object, and
>>one of them calls release, what happens to all of the others?

The release function should release the pointer only if "unique() ==
true"
In three scenarios:

1) using the default deleter:
template<class Y> bool release(auto_ptr<Y>& sp)

Transfers ownewship to auto_ptr if:
- unique() == true
- and using the default deleter

Returns true if succeeded, false otherwise
I know that is a very specialized function, but it works fine and
it's safe.

2) Using custom deleter
In this case returning the pointer and the deleter.( it works, but I
believe is not so elegant and safe function).

3) Using custom deleter and new type of auto_ptr.
Returning auto_ptr_d (new class that can hold and use the deleter)
template<class Y > bool release(auto_ptr_d<Y>& sp)

I think is better to use something that is generic and exists in the
standard (or will exist in this case) instead create a new class.
However, if it is not possible, the "ptr_vector_builder" or one more
generic "ptr_container_builder" is a good solution.

I don't like to use a try catch blocks because probably we will need to
do the same code in another function.


--

James Kanze

unread,
Jan 4, 2007, 4:06:35 PM1/4/07
to
Thiago Adams wrote:
> >>If multiple shared_ptrs are sharing ownership of the same object, and
> >>one of them calls release, what happens to all of the others?

> The release function should release the pointer only if "unique() ==
> true"

Which means that after calling release, I have no way of knowing
whether I should delete the memory or not.

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Thiago Adams

unread,
Jan 4, 2007, 4:00:08 PM1/4/07
to
> I think is better to use something that is generic and exists in the
> standard (or will exist in this case) instead create a new class.
> However, if it is not possible, the "ptr_vector_builder" or one more
> generic "ptr_container_builder" is a good solution.

Complementing...
If I have to create one "ptr_container_builder" maybe is better to
create one "ptr_container" who has the ownership of the pointers by
default. (Deleting pointers on clear, remove etc...)

I think that one of the most common constructs in frameworks is a class
that has some container holding pointers.

Greg Herlihy

unread,
Jan 4, 2007, 4:34:31 PM1/4/07
to
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.

What is an "exception safe" function exactly?

> 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);
> }

Why not insert the items into the vector directly? What does the local
vector contribute to this routine? I suspect that you are interested in
ensuring the atomicity or "idempotency" of the operation of filling the
vector. In other words, when adding a particular set of items to a
vector, either all of the items are to be added or no items are to be
added. But in that case why not simply clear the vector when the
exception thown when one of the items cannot be added - is caught:

void (vector< shared_ptr<Item> >& vec)
{
try {


for (int i = 0; i < N, i++)

vec.push_back( shared_ptr<Item>(new Item(i)) );
}
catch (...)
{
vec.clear();
throw;
}
}

> 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 * >.

Why swap? Why not copy the pointers frorm the shared_ptr vector into
the pointer vector:

#include <algorithm>
#include <vector>
#include <functional>

using std::tr1::shared_ptr;
using std::vector;
using std::mem_fun_ref;

typedef shared_ptr<Item> ItemPtr;

...
vector< ItemPtr> v;
vector< Item*> v2;

...

v2.resize( v.size());
std::transform( v.begin(), v.end(), v2.begin(),
mem_fun_ref(&ItemPtr::get));

> 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?

I don't see how a custom container would implement the behavior you
want. A custom class to wrap the shared_ptr should work:

#include <algorithm>
#include <vector>
#include <functional>
#include <stdexcept>

using std::vector;
using std::mem_fun_ref;
using std::tr1::shared_ptr;

struct Item
{
Item(int i) {}
~Item() { std::cout << "deleting Item\n" ; }
};

struct released_deleter
{
public:
released_deleter() : released_(false) {}

void release() { released_ = true; }

template <class T>
void operator()( const T* t)
{
if (not released_)
delete t;
else
std::cout << "not deleting Item\n";
}

private:
bool released_;
};

class ItemPtr
{
public:
explicit ItemPtr(int i)
: ptr_(new Item(i), released_deleter())
{
}

Item* operator->() { return ptr_.get(); }
Item* get() { return ptr_.get(); }

void release()
{
if (not ptr_.unique())
throw std::runtime_error("released ptr not unique");

std::tr1::get_deleter<released_deleter>( ptr_)->release();
}

private:
shared_ptr<Item> ptr_;
};

int main()
{
vector< ItemPtr> v;

v.push_back( ItemPtr(1) );
v.push_back( ItemPtr(2) );
v.push_back( ItemPtr(3) );
v.push_back( ItemPtr(4) );

v.clear();

v.push_back( ItemPtr(1) );
v.push_back( ItemPtr(2) );
v.push_back( ItemPtr(3) );
v.push_back( ItemPtr(4) );

std::for_each( v.begin(), v.end(),
mem_fun_ref(&ItemPtr::release));

v.clear();
}

Program Output:

deleting Item
deleting Item
deleting Item
deleting Item
not deleting Item
not deleting Item
not deleting Item
not deleting Item

Greg

Howard Hinnant

unread,
Jan 5, 2007, 3:04:58 PM1/5/07
to
In article <1167747311....@v33g2000cwv.googlegroups.com>,
"Thiago Adams" <thiago...@gmail.com> wrote:

> 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);
> }

I can't help you today. But there is a C++0X solution to your problem.
I'm presenting it here so that you know a solution is on the way.
Unfortunately you'll still have to work out a workaround until your
vendor comes up to speed. But know that adding a release function to
shared_ptr (which is also std in C++0X) may not be the best interim
workaround since by the time we get std::shared_ptr, we should also have
the functionality below:

std::vector<std::unique_ptr<Item>> func(int N)
{
std::vector<std::unique_ptr<Item>> local;


for (int i = 0; i < N, i++)
{

local.push_back(std::unique_ptr<Item>(new Item(i)));
}
return local;
}

At first glance you may look on this with horror: passing a vector
around by value?! Well, not really. This use of vector will either
elide the "copy" on return, or "move" it out. C++0X will be prohibited
from copying "local" out. That means that even if you have something
like:

vector<unique_ptr<Item>> v;
v = func(N);

It is guaranteed that new Item will only be called N times (inside of
func). And once local is fully constructed within func, no other
allocations take place.

Think of unique_ptr as the same thing as auto_ptr, just safe to put into
vector. It has unique ownership semantics, just like auto_ptr. It has
the same overhead as auto_ptr. It even has release().

And the func() outlined below has a strong exception safety guarantee.
If an exception is thrown while forming "local", nothing else is
affected, and "local" is completely cleaned up.

In the near future you will be able to pass vectors around "by value" in
many cases (such as the one above) without incurring an O(N) cost.

-Howard

Thiago Adams

unread,
Jan 5, 2007, 3:18:58 PM1/5/07
to

Greg Herlihy wrote:
> What is an "exception safe" function exactly?
No memory leaks if the "Item" constructor or push_back throws.

> Why not insert the items into the vector directly? What does the local
> vector contribute to this routine? I suspect that you are interested in
> ensuring the atomicity or "idempotency" of the operation of filling the
> vector. In other words, when adding a particular set of items to a
> vector, either all of the items are to be added or no items are to be
> added. But in that case why not simply clear the vector when the
> exception thown when one of the items cannot be added - is caught:

I used the swap just to implement the strong guarantee. But it is not
the main problem, it could be implemented using clear.

> Why swap? Why not copy the pointers frorm the shared_ptr vector into
> the pointer vector:

Yes, it's indifferent. Using "shared_ptr.release" I also need to
copy.

> struct released_deleter

The custon deleter is is a very interesting solution!!

But we also need to create a very specialized code. In this case, maybe
is better to create the "vector_builder" (it is more efficient). I
don't know if is possible to create an adapter to use the auto_ptr
inside STL containers? Something likes the CAdapt from ATL for
auto_ptr.

I have implemented the release method in the shared_ptr just to test.
The implementation is on my website:
http://paginas.terra.com.br/informatica/thiago_adams/shared_ptr2.htm
I think that the unique == true is not the only condition to release.
We need take care about the weak_ptr's as well.

Maybe creating the loop to removed items is the best way to implement,
even considering the duplicated code. :-/

Dizzy

unread,
Jan 5, 2007, 4:19:17 PM1/5/07
to
James Kanze wrote:

> Thiago Adams wrote:
>> >>If multiple shared_ptrs are sharing ownership of the same object, and
>> >>one of them calls release, what happens to all of the others?
>
>> The release function should release the pointer only if "unique() ==
>> true"
>
> Which means that after calling release, I have no way of knowing
> whether I should delete the memory or not.

Hmm, release() should set the pointed to value to 0 (like auto_ptr<>) or
whatever default value sets to meaning the shared_ptr<> is not owning
anything anymore thus no problem after that deciding whether the memory
should be released or not.

--
Dizzy
http://dizzy.roedu.net

Greg Herlihy

unread,
Jan 6, 2007, 11:48:40 AM1/6/07
to

Thiago Adams wrote:
> The custon deleter is is a very interesting solution!!
>
> But we also need to create a very specialized code. In this case, maybe
> is better to create the "vector_builder" (it is more efficient). I
> don't know if is possible to create an adapter to use the auto_ptr
> inside STL containers? Something likes the CAdapt from ATL for
> auto_ptr.
> We need take care about the weak_ptr's as well.

To handle weak_ptrs correctly, ItemPtr::release() just has to combine a
few operations, namely: to assume ownership of the shared_ptr's
pointer, reset the shared_ptr, and return the emancipated pointer to
the caller. Once these changes are made, the weak_ptr problem is
solved.

To implement this solution, first add a get_weak_ptr() method to
ItemPtr:

weak_ptr<Item>
ItemPtr::get_weak_ptr() const
{
return weak_ptr<Item>(ptr_);
}

Now implement the ItemPtr::release() method:

Item* ItemPtr::release()


{
if (not ptr_.unique())
throw std::runtime_error("released ptr not unique");

Item * p = ptr_.get();

std::tr1::get_deleter<released_deleter>( ptr_)->release();

ptr_.reset();
return p;
}

And finally run this revised main() to try out this new design:

int main()
{
vector<ItemPtr> v;

v.push_back( ItemPtr(1) );

weak_ptr<Item> wp = v.front().get_weak_ptr();

std::cout << "weak_ptr expired: ";
std::cout << std::boolalpha << wp.expired() << "\n";

vector< Item* > v2( v.size() );

transform( v.begin(), v.end(), v2.begin(),
mem_fun_ref( &ItemPtr::release ));

std::cout << "weak_ptr expired: ";
std::cout << std::boolalpha << wp.expired() << "\n";

v.clear();
}

Program Output:

weak_ptr expired: false
not deleting Item
weak_ptr expired: true

Greg

Carl Barron

unread,
Jan 6, 2007, 11:48:11 AM1/6/07
to
In article <459e453b$0$49209$1472...@news.sunsite.dk>, Dizzy
<di...@roedu.net> wrote:

> James Kanze wrote:
>
> > Thiago Adams wrote:
> >> >>If multiple shared_ptrs are sharing ownership of the same object, and
> >> >>one of them calls release, what happens to all of the others?
> >
> >> The release function should release the pointer only if "unique() ==
> >> true"
> >
> > Which means that after calling release, I have no way of knowing
> > whether I should delete the memory or not.
>
> Hmm, release() should set the pointed to value to 0 (like auto_ptr<>) or
> whatever default value sets to meaning the shared_ptr<> is not owning
> anything anymore thus no problem after that deciding whether the memory
> should be released or not.

I see no need for release()...

a simple
std::auto_ptr<Item> convert(shared_ptr<Item> &p) // call by reference
{
std::auto_ptr a(new Item(*p));
p.reset; // reduces count by one, etc. other copies
// this copy is now a default shared_ptr.
return a;
}

converts the shared_ptr to a default shared_ptr and returns
an auto_ptr containing the data ptr.

It is possible to possibly optimize this if the deleter of the
shared_ptr can be set at runtime to do nothing and the shared_ptr is
unique ,just moving ptrs around with public functions of shared_ptr and
the auto_ptr ctor.

--

thiago...@hotmail.com

unread,
Jan 7, 2007, 10:38:47 AM1/7/07
to
Greg Herlihy wrote:

> Thiago Adams wrote:
> > The custon deleter is is a very interesting solution!!
> >
> > But we also need to create a very specialized code. In this case, maybe
> > is better to create the "vector_builder" (it is more efficient). I
> > don't know if is possible to create an adapter to use the auto_ptr
> > inside STL containers? Something likes the CAdapt from ATL for
> > auto_ptr.
> > We need take care about the weak_ptr's as well.
>
> To handle weak_ptrs correctly, ItemPtr::release() just has to combine a
> few operations, namely: to assume ownership of the shared_ptr's
> pointer, reset the shared_ptr, and return the emancipated pointer to
> the caller. Once these changes are made, the weak_ptr problem is
> solved.

Considering that the shared_ptr is private in ItemPtr I think is not
possible to create weak_ptrs. So is not necessary to worry about them
in this solution. Unless that the get_weak_ptr has been created.


Actually, I was trying to find one possible solution for the problem
using shared_ptr as an auto_ptr in containers. The release function was
necessary to do this.

Unfortunately we need to wait for the move semantics to have a better
auto_ptr.
(or not)?

James Kanze

unread,
Jan 7, 2007, 11:51:49 AM1/7/07
to
Greg Herlihy wrote:

> What is an "exception safe" function exactly?

One that has documented behavior in the case of an exception,
and conforms to that documented behavior. In addition, it must
not leak memory, for example, or cause any other internal
inconsistencies that later code cannot possibly repare.

--
James Kanze (Gabi Software) email: james...@gmail.com


Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

James Kanze

unread,
Jan 7, 2007, 11:51:27 AM1/7/07
to
Dizzy wrote:
> James Kanze wrote:

> > Thiago Adams wrote:
> >> >>If multiple shared_ptrs are sharing ownership of the same object, and
> >> >>one of them calls release, what happens to all of the others?

> >> The release function should release the pointer only if "unique() ==
> >> true"

> > Which means that after calling release, I have no way of knowing
> > whether I should delete the memory or not.

> Hmm, release() should set the pointed to value to 0 (like auto_ptr<>) or
> whatever default value sets to meaning the shared_ptr<> is not owning
> anything anymore thus no problem after that deciding whether the memory
> should be released or not.

I'm not sure I understand. If unique() is true, the pointer is
released, and it is the responsibility of the caller to delete
it. If unique() is not true, the pointer is not released, and
the caller should not delete it.

--
James Kanze (Gabi Software) email: james...@gmail.com


Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


--

thiago...@hotmail.com

unread,
Jan 7, 2007, 11:53:27 AM1/7/07
to

Howard Hinnant wrote:
> I can't help you today. But there is a C++0X solution to your problem.
> I'm presenting it here so that you know a solution is on the way.
> Unfortunately you'll still have to work out a workaround until your
> vendor comes up to speed. But know that adding a release function to
> shared_ptr (which is also std in C++0X) may not be the best interim
> workaround since by the time we get std::shared_ptr, we should also have
> the functionality below:

Yes, I agree. I think that the release function in shared_ptr is not
necessary considering the existence of the unique_ptr.
The solution using moving semantics is really elegant.

I had one more idea to implement this function. The auto_ptr solves the
exception safe problem for one item very well. All we need is to solve
the problem for N items.
So, I have tested a recursive functions to create N auto_ptrs and it
works fine. I am now trying to generalize this recursive functions to
be used as an algorithm to create/insert objects into containers.
(Maybe this solution is efficient as well)

struct Item
{
int i;
Item(int i) : i(i)
{
cout << "constructing item " << i << endl;
if (i == 5) throw std::exception("Exception to test fail");
}
~Item()
{
cout << "destroying item " << i << endl;
}
};

void CreateItem(vector<Item*> & vec, int & n)
{
if (n == 10)
return;
auto_ptr<Item> ap(new Item(n));
vec.push_back(ap.get());
n++;
CreateItem(vec, n);
ap.release();
}

void GetItems(vector<Item*> &vec)
{
vector<Item*> local;
int i = 0;
CreateItem(local, i);
local.swap(vec);
}

int main()
{
vector<Item*> items;
try
{
GetItems(items);

vector<Item*>::iterator it = items.begin();
for( ; it != items.end(); ++it)
delete *it;
}
catch(const std::exception & e)
{
cout << e.what();

Chris Thomasson

unread,
Jan 7, 2007, 6:19:21 PM1/7/07
to
"Thiago Adams" <thiago...@gmail.com> wrote in message
news:1167747311....@v33g2000cwv.googlegroups.com...

>
> 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 created a release function for my atomic counting:

http://appcore.home.comcast.net/vzoom/refcount/
(I haven't updated the code on my site yet, so it does not have a release
function...
also, the load_refcount_ptr() shown in the following pseudo-code is not
there as well..)


Anyway, I think you will see exactly what I am doing here... I used
release() like this:

<super pseudo-code>
--------------

extern "C" {
static void* thread_proc(...);
}

namespace thread {
namespace impl {
struct thread_sys {
typedef vzsync::ptr::global gptr_t;
typedef vzsync::ptr::local lptr_t;
...
};
}

typedef impl::thread_sys::gptr ghandle_t;
typedef impl::thread_sys::lptr lhandle_t;

static lhandle_t create(...) {
// create 2 local refs... one for the caller, and the
//other for the yet to be created thread
lhandle_t _this(new impl::thread_sys(...));
lhandle_t _tref(_this);

// count is now 2...
// if exception thrown, _this gets dtor... fine...
os_thread_create(::thread_proc, _this.load_refcount_ptr());

// okay, no chance of throwing now, and the
// reference is transfered to the thread...
// so, we prevent the _tref from decrement on scope_exit.

_tref.release();

// now we return a local reference to the handle to the caller
return _this;
}
}

extern "C" {
void* thread_proc(...) {
// we grab the ptr, but we do not increment or we leak by one!
thread::lhandle_t _this(..., 0);

// okay, we received the transferred count... When _this goes out of
// scope, the transfered reference will be decremented by 1...

// notify the base class that the "C" proc has done its thing!
// exceptions here are 100% fine...
_this->sys_on_entry();

return 0;
}
}


I had to use release here in order to prevent the count from becoming a
value that would segfault my rercount algorithm; the docs explain the rules:

http://appcore.home.comcast.net/vzoom/refcount/doc/


So, I guess I can see how release could be useful.

Any thoughts?

Howard Hinnant

unread,
Jan 8, 2007, 2:06:11 AM1/8/07
to
In article <1168127759.3...@s80g2000cwa.googlegroups.com>,
thiago...@hotmail.com wrote:

> Unfortunately we need to wait for the move semantics to have a better
> auto_ptr.
> (or not)?

Emulations of unique_ptr exist today (e.g.
http://home.twcny.rr.com/hinnant/cpp_extensions/unique_ptr_03.html ).
However I don't think they will help you as you can't put one into a
container.

Probably your best bet today is a container designed to hold pointers
which it owns. E.g.
http://www.boost.org/libs/ptr_container/doc/ptr_container.html .

-Howard

Howard Hinnant

unread,
Jan 8, 2007, 2:06:11 AM1/8/07
to

> Unfortunately we need to wait for the move semantics to have a better
> auto_ptr.
> (or not)?

Emulations of unique_ptr exist today (e.g.


http://home.twcny.rr.com/hinnant/cpp_extensions/unique_ptr_03.html ).
However I don't think they will help you as you can't put one into a
container.

Probably your best bet today is a container designed to hold pointers
which it owns. E.g.
http://www.boost.org/libs/ptr_container/doc/ptr_container.html .

-Howard

--

0 new messages