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

which pointer

0 views
Skip to first unread message

Nick Keighley

unread,
Dec 11, 2009, 10:58:53 AM12/11/09
to
I wanted my code to look something like this

void new_call (Msg& msg)
{
smart_ptr<Call> call_ptr ();
CallList::add (*call_ptr); // may throw
Call *call = call.release();
call.process_msg (msg);
}

now that may not be quite right, but the aim was to allocate a Call
and store it in CallList. If CallList throws the smart_ptr will
destroy the Call, otherwise process the message and the call remains
in the CallList for more message processing.

smart_ptr would not allow copy or assignment. Release returns the
pointer value and zeros its record. I was going to call it
ExplicitReleasePointer. But then I thought,surely boost have already
done this. Aha! scoped_ptr! Oops no. No release(). The rationale for
this is that scoped_ptr implies no transfer of ownership. But I want
to transfer ownership. That I should use auto_ptr if I want transfer
of ownership semantics. But how do I coerce auto_ptr into doing the
cleanup. Should I be making my container class do the cleanup? Or
should I be using shared_ptr in both the container class and my
calling function?

My thought was that I didn't want the container class to do the
deletion as the caller might want to do with the something with the
Call even in the failure case (log data from the call or pass the call
to someone else to deal with).

I suppose the logic is that ownership is shared so you need a shared
pointer.

Victor Bazarov

unread,
Dec 11, 2009, 11:19:46 AM12/11/09
to
Nick Keighley wrote:
> I wanted my code to look something like this
>
> void new_call (Msg& msg)
> {
> smart_ptr<Call> call_ptr ();

Declared a function.

> CallList::add (*call_ptr); // may throw

Dereferenced a function???

> Call *call = call.release();

If 'call' is a pointer, the dot operator cannot be used with it, not to
mention it's not initialized yet...

> call.process_msg (msg);

Again, if 'call' is a pointer (as you declared just above), there is no
"dot" operator for it.

> }
>
> now that may not be quite right,

You bet your sweet donkey it isn't. Post real code, please.

> but the aim was to allocate a Call
> and store it in CallList. If CallList throws the smart_ptr will
> destroy the Call, otherwise process the message and the call remains
> in the CallList for more message processing.
>
> smart_ptr would not allow copy or assignment. Release returns the
> pointer value and zeros its record. I was going to call it
> ExplicitReleasePointer. But then I thought,surely boost have already
> done this. Aha! scoped_ptr! Oops no. No release(). The rationale for
> this is that scoped_ptr implies no transfer of ownership. But I want
> to transfer ownership. That I should use auto_ptr if I want transfer
> of ownership semantics.

The last sentence makes no sense.

> But how do I coerce auto_ptr into doing the
> cleanup.

"Coerce"?

> Should I be making my container class do the cleanup?

Who owns the object? And if it is at different points in your program,
do specify that. Cleanup is done by the owner.

> Or
> should I be using shared_ptr in both the container class and my
> calling function?

Probably. The ownership transfer is automatic then.

> My thought was that I didn't want the container class to do the
> deletion as the caller might want to do with the something with the

"with the something with the"?

> Call even in the failure case (log data from the call or pass the call
> to someone else to deal with).

Uh... OK. Where is the spec? Is that the spec? It doesn't really
look or sound like one...

> I suppose the logic is that ownership is shared so you need a shared
> pointer.

Perhaps you should start by trying to describe the algorithm and
indicate who owns what at every point.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

Paavo Helde

unread,
Dec 11, 2009, 1:45:02 PM12/11/09
to
Nick Keighley <nick_keigh...@hotmail.com> wrote in news:81377349-
fdb9-4d2f-985...@j14g2000yqm.googlegroups.com:

> I wanted my code to look something like this
>
> void new_call (Msg& msg)
> {
> smart_ptr<Call> call_ptr ();
> CallList::add (*call_ptr); // may throw
> Call *call = call.release();
> call.process_msg (msg);
> }
>
> now that may not be quite right, but the aim was to allocate a Call
> and store it in CallList. If CallList throws the smart_ptr will
> destroy the Call, otherwise process the message and the call remains
> in the CallList for more message processing.
>
> smart_ptr would not allow copy or assignment. Release returns the
> pointer value and zeros its record. I was going to call it
> ExplicitReleasePointer. But then I thought,surely boost have already
> done this. Aha! scoped_ptr! Oops no. No release(). The rationale for
> this is that scoped_ptr implies no transfer of ownership. But I want
> to transfer ownership. That I should use auto_ptr if I want transfer
> of ownership semantics. But how do I coerce auto_ptr into doing the
> cleanup. Should I be making my container class do the cleanup? Or
> should I be using shared_ptr in both the container class and my
> calling function?

If I understand correctly, then you want something like ScopeGuard (look
it up):

#include <ScopeGuard/ScopeGuard.h>

template <class T> struct Delete {
void operator()(T *t) const { delete t;}
};

void new_call (Msg& msg)
{
Call* call_ptr = new Call();
// assume ownership
ScopeGuard guard = MakeGuard( Delete<Call>(), call_ptr);

// pass object to container, container will assume
// ownership iff the call does not throw.
CallList::add(call_ptr); // may throw

// give up my ownership
guard.Dismiss();

// call a method on the object owned by the container
call_ptr->process_msg (msg);
}

>
> I suppose the logic is that ownership is shared so you need a shared
> pointer.
>


Yes, a cleaner way would be to use boost::shared_ptr both in the
container and in the caller function.

hth
Paavo


James Kanze

unread,
Dec 13, 2009, 5:56:17 AM12/13/09
to
On Dec 11, 3:58 pm, Nick Keighley <nick_keighley_nos...@hotmail.com>
wrote:

> I wanted my code to look something like this

> void new_call (Msg& msg)
> {
> smart_ptr<Call> call_ptr ();
> CallList::add (*call_ptr); // may throw
> Call *call = call.release();
> call.process_msg (msg);
> }

> now that may not be quite right, but the aim was to allocate a
> Call and store it in CallList. If CallList throws the
> smart_ptr will destroy the Call, otherwise process the message
> and the call remains in the CallList for more message
> processing.

> smart_ptr would not allow copy or assignment.

Which smart_ptr? (I am supposing that "smart_ptr", here, is a
generic name for a set of smart pointers, e.g. std::auto_ptr,
boost::scoped_ptr, boost::shared_ptr, etc. If not: I have no
idea what the class does.) Some do, some don't.

> Release returns the pointer value and zeros its record. I was
> going to call it ExplicitReleasePointer. But then I
> thought,surely boost have already done this. Aha! scoped_ptr!
> Oops no. No release(). The rationale for this is that
> scoped_ptr implies no transfer of ownership. But I want to
> transfer ownership. That I should use auto_ptr if I want
> transfer of ownership semantics. But how do I coerce auto_ptr
> into doing the cleanup. Should I be making my container class
> do the cleanup? Or should I be using shared_ptr in both the
> container class and my calling function?

I'm not sure what you mean by "cleanup", or when it should
occur. One common idiom is to use auto_ptr until the newly
created object has registered itself somewhere, so that it can
be found by future events. Generally, in such cases, one of
those future events will trigger the destruction of the object
("delete this"), and the destructor will do all necessary
clean-up (including deregistering the object).

Alternatively, if the object should cease to exist at the end of
the function (although with a name like new_call, it doesn't
sound like it), then you should probably use a local variable,
and skip dynamic allocation entirely. (Again, deregistration
would be taken care of in the destructor.)

> My thought was that I didn't want the container class to do
> the deletion as the caller might want to do with the something
> with the Call even in the failure case (log data from the call
> or pass the call to someone else to deal with).

Just to be clear, by "container class", you really mean some
sort of registry. The allocated object can't be contained; at
best, a copy of it can be contained, but if the object supports
copy, you probably don't want dynamic allocation to begin with.

> I suppose the logic is that ownership is shared so you need a
> shared pointer.

I sort of doubt that. If the object is registering itself in
some sort of registry, the logic is more likely no ownership.
It's an entity object, capable of taking care of itself.

--
James Kanze

Nick Keighley

unread,
Jan 4, 2010, 7:03:35 AM1/4/10
to
On 11 Dec 2009, 16:19, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> NickKeighleywrote:

> > I wanted my code to look something like this
>
> > void new_call (Msg& msg)
> > {
> >        smart_ptr<Call> call_ptr ();
>
> Declared a function.
>
> >        CallList::add (*call_ptr);        // may throw
>
> Dereferenced a function???
>
> >        Call *call = call.release();
>
> If 'call' is a pointer, the dot operator cannot be used with it, not to
> mention it's not initialized yet...
>
> >        call.process_msg (msg);
>
> Again, if 'call' is a pointer (as you declared just above), there is no
> "dot" operator for it.
>
> > }
>
> > now that may not be quite right,
>
> You bet your sweet donkey it isn't.  Post real code, please.

ok, fair point

// a smart pointer question

#include <memory>
#include <vector>
using namespace std;

class Msg
{
public:
Msg()
{}
};

class Call
{
public:
explicit Call(Msg& msg): msg_(msg)
{}

void process_msg(Msg&)
{}

private:
Msg& msg_;
};

class CallList
{
public:
static void add (Call* call)
{
vec_.push_back( call);
}

private:
static vector<Call*> vec_;
};

vector<Call*> CallList::vec_;

void new_call (Msg& msg)
{
auto_ptr<Call> call_ptr (new Call(msg)); // auto_ptr may not b
what I want
CallList::add (call_ptr.get()); // may throw
Call* call = call_ptr.release();
call->process_msg (msg);
}

int main (void)
{
Msg msg;
new_call (msg);
return 0;
}

this at least compiles.


>  > but the aim was to allocate a Call
>
> > and store it in CallList. If CallList throws the smart_ptr will
> > destroy the Call, otherwise process the message and the call remains
> > in the CallList for more message processing.
>
> > smart_ptr would not allow copy or assignment. Release returns the
> > pointer value and zeros its record. I was going to call it
> > ExplicitReleasePointer. But then I thought,surely boost have already
> > done this. Aha! scoped_ptr! Oops no. No release(). The rationale for
> > this is that scoped_ptr implies no transfer of ownership. But I want
> > to transfer ownership. That I should use auto_ptr if I want transfer
> > of ownership semantics.
>
> The last sentence makes no sense.

perhaps this is better:

The rationale for [scoped_ptr lacking a release()] is that scoped_ptr
implies no transfer of ownership (but I want to transfer ownership),
and that auto_ptr should be used if transfer of ownership semantics is
required.

This may be wrong but should at least make sense.

>  > But how do I coerce auto_ptr into doing the cleanup.
>
> "Coerce"?

make it? get it to do? ask it to?

>  > Should I be making my container class do the cleanup?
>
> Who owns the object?

if the add succeeds the container. If it fails the smart_ptr.

> And if it is at different points in your program,

if it is owned by different things at different points in the program?

> do specify that.  

I thought I did

> Cleanup is done by the owner.

ok...

>  > Or
>
> > should I be using shared_ptr in both the container class and my
> > calling function?
>
> Probably.  The ownership transfer is automatic then.

ok, thanks

> > My thought was that I didn't want the container class to do the
> > deletion as the caller might want to do with the something with the
>
> "with the something with the"?

"do somethign with the call on failure"- say stuff a special call end
reason or something.


> > Call even in the failure case (log data from the call or pass the call
> > to someone else to deal with).
>
> Uh...  OK.  Where is the spec?  Is that the spec?  It doesn't really
> look or sound like one...

its a rather waffly vague spec. Allocate an object. Put it in a
container. If something goes wrong call the object's dtor.


> > I suppose the logic is that ownership is shared so you need a shared
> > pointer.
>
> Perhaps you should start by trying to describe the algorithm and
> indicate who owns what at every point.

I was attempting that.

Nick Keighley

unread,
Jan 4, 2010, 7:09:35 AM1/4/10
to
On 13 Dec 2009, 10:56, James Kanze <james.ka...@gmail.com> wrote:
> On Dec 11, 3:58 pm, NickKeighley<nick_keighley_nos...@hotmail.com>
> wrote:


> > I wanted my code to look something like this
>
> > void new_call (Msg& msg)
> > {
> >        smart_ptr<Call> call_ptr ();
> >        CallList::add (*call_ptr);        // may throw
> >        Call *call = call.release();
> >        call.process_msg (msg);
> > }
> > now that may not be quite right,

no, see my earlier 2010 post.


> > but the aim was to allocate a
> > Call and store it in CallList. If CallList throws the
> > smart_ptr will destroy the Call, otherwise process the message
> > and the call remains in the CallList for more message
> > processing.
> > smart_ptr would not allow copy or assignment.
>
> Which smart_ptr?  

that was the question (actually the title of the post). I was asking
which smart ptr I should be using. Is there a standard one that does
what I want I do I need to write one?


> (I am supposing that "smart_ptr", here, is a
> generic name for a set of smart pointers, e.g. std::auto_ptr,
> boost::scoped_ptr, boost::shared_ptr, etc.  If not: I have no
> idea what the class does.)  Some do, some don't.
>
> > Release returns the pointer value and zeros its record. I was
> > going to call it ExplicitReleasePointer. But then I
> > thought,surely boost have already done this. Aha! scoped_ptr!
> > Oops no. No release(). The rationale for this is that
> > scoped_ptr implies no transfer of ownership. But I want to
> > transfer ownership. That I should use auto_ptr if I want
> > transfer of ownership semantics. But how do I coerce auto_ptr
> > into doing the cleanup. Should I be making my container class
> > do the cleanup? Or should I be using shared_ptr in both the
> > container class and my calling function?
>
> I'm not sure what you mean by "cleanup",

well, generally call the dtor

> or when it should
> occur.  One common idiom is to use auto_ptr until the newly
> created object has registered itself somewhere, so that it can
> be found by future events.  Generally, in such cases, one of
> those future events will trigger the destruction of the object
> ("delete this"), and the destructor will do all necessary
> clean-up (including deregistering the object).

this sounds exactly what I want.

> Alternatively, if the object should cease to exist at the end of
> the function (although with a name like new_call, it doesn't
> sound like it),

no

> then you should probably use a local variable,
> and skip dynamic allocation entirely.  (Again, deregistration
> would be taken care of in the destructor.)
>
> > My thought was that I didn't want the container class to do
> > the deletion as the caller might want to do with the something
> > with the Call even in the failure case (log data from the call
> > or pass the call to someone else to deal with).
>
> Just to be clear, by "container class", you really mean some
> sort of registry.

if that's the appropriate terminology. It contains calls...


> The allocated object can't be contained; at
> best, a copy of it can be contained,

or a pointer

> but if the object supports
> copy, you probably don't want dynamic allocation to begin with.

I can't know in advance how many calls there will be.


> > I suppose the logic is that ownership is shared so you need a
> > shared pointer.
>
> I sort of doubt that.  If the object is registering itself in
> some sort of registry, the logic is more likely no ownership.
> It's an entity object, capable of taking care of itself.

?

self deleteing?

James Kanze

unread,
Jan 4, 2010, 5:08:24 PM1/4/10
to
On Jan 4, 12:09 pm, Nick Keighley <nick_keighley_nos...@hotmail.com>
wrote:

> On 13 Dec 2009, 10:56, James Kanze <james.ka...@gmail.com> wrote:
> > > but the aim was to allocate a Call and store it in
> > > CallList. If CallList throws the smart_ptr will destroy
> > > the Call, otherwise process the message and the call
> > > remains in the CallList for more message processing.
> > > smart_ptr would not allow copy or assignment.

> > Which smart_ptr?

> that was the question (actually the title of the post). I was
> asking which smart ptr I should be using. Is there a standard
> one that does what I want I do I need to write one?

To answer that, I'd have to know exactly what you want to do.
What is the lifetime of the pointed to object? Does it have
identity? Must it be polymorphic?

It's a frequent idiom for objects that can handle events (and
for which one of the events triggers destruction). In such
cases, there are two possible solutions: the constructor of the
object enregisters the object with the event handler, and you
might not even need to maintain a pointer to it (outside of the
event handler) at all---I've more than a couple of cases where
I've written "new SomeType" without assigning the results of the
new to any pointer whatsoever. If for some reason, this isn't
possible, the best solution is generally to save the results of
new in an auto_ptr until the object has been correctly enrolled,
and then call release on the auto_ptr.

[...]


> > Just to be clear, by "container class", you really mean some
> > sort of registry.

> if that's the appropriate terminology. It contains calls...

That's not really sufficient. What I mean is that the container
is somehow used to find the object, say when an external event
arrives.

> > The allocated object can't be contained; at
> > best, a copy of it can be contained,

> or a pointer

But the semantics of containing a pointer and containing an
object are radically different. Which semantics do you want?

> > but if the object supports copy, you probably don't want
> > dynamic allocation to begin with.

> I can't know in advance how many calls there will be.

But if the object supports copy, it doesn't matter.

Does the object have an identity, or no?

> > > I suppose the logic is that ownership is shared so you need a
> > > shared pointer.

> > I sort of doubt that. If the object is registering itself in
> > some sort of registry, the logic is more likely no ownership.
> > It's an entity object, capable of taking care of itself.

> ?

> self deleteing?

Yes. If the object reacts to events, one of those events could
very easily result in a demand that the object cease to exist.
In my own code, I'd guess that well over half of the calls to
delete are "delete this".

--
James Kanze

Noah Roberts

unread,
Jan 7, 2010, 11:58:57 AM1/7/10
to
In article <95aa7504-d2d5-47fa-8191-f4484d45e371
@m26g2000yqb.googlegroups.com>, nick_keigh...@hotmail.com says...

> > ᅵ> but the aim was to allocate a Call


> >
> > > and store it in CallList. If CallList throws the smart_ptr will
> > > destroy the Call, otherwise process the message and the call remains
> > > in the CallList for more message processing.
> >
> > > smart_ptr would not allow copy or assignment. Release returns the
> > > pointer value and zeros its record. I was going to call it
> > > ExplicitReleasePointer. But then I thought,surely boost have already
> > > done this. Aha! scoped_ptr! Oops no. No release(). The rationale for
> > > this is that scoped_ptr implies no transfer of ownership. But I want
> > > to transfer ownership. That I should use auto_ptr if I want transfer
> > > of ownership semantics.

It seems to me that the above code does what you want, right? Coming
into this conversation late, but based on the above I'd say the code is
what you want. I don't think that any of the other "standard" smart
pointers would give you what you want.

It might be though that what you want is not a smart pointer but a scope
guard:

template < typename T >
struct heap_scope_guard // just does heap memory protection
{
explicit heap_scope_guard(T * t) : resource(t), released(false) {}
~heap_scope_guard() { if (!released) delete resource; }
void release() { released = true; }
private:
T * resource;
bool released;
};

Your code would then be:

void new_call (Msg& msg)
{
Call * call_ptr;
heap_scope_guard<Call> guard(call_ptr);
CallList::add (call_ptr);
guard.release();
call_ptr->process_msg (msg);
}


You could add more, change a few things the way you want. Technically
this would be the "correct" way to do what you want as the auto_ptr is
actually providing more functionality than you actually need/want.
However, I don't think this fact is enough to warrant the extra
development and unit testing for writing a scope guard unless you have
uses for it elsewhere (though it's not really that much). I don't
generally do a bunch of extra development for something THAT pedantic.

Up to you, just a different idea.

James Kanze

unread,
Jan 7, 2010, 4:44:21 PM1/7/10
to
On Jan 7, 4:58 pm, Noah Roberts <d...@reply.com> wrote:
> In article <95aa7504-d2d5-47fa-8191-f4484d45e371
> @m26g2000yqb.googlegroups.com>, nick_keighley_nos...@hotmail.com says...

[...]


> > > > smart_ptr would not allow copy or assignment. Release
> > > > returns the pointer value and zeros its record. I was
> > > > going to call it ExplicitReleasePointer. But then I
> > > > thought,surely boost have already done this. Aha!
> > > > scoped_ptr! Oops no. No release(). The rationale for
> > > > this is that scoped_ptr implies no transfer of
> > > > ownership. But I want to transfer ownership. That I
> > > > should use auto_ptr if I want transfer of ownership
> > > > semantics.

> It seems to me that the above code does what you want, right?

That's my impression as well. This is a standard idiom, or if
it isn't, it should be. Allocate to auto_ptr. Once the object
has "established" itself (registered for events, or whatever
else is necessary for it to behave correctly in the normal
course of the programs events), call release on auto_ptr.

> Coming into this conversation late, but based on the above I'd
> say the code is what you want. I don't think that any of the
> other "standard" smart pointers would give you what you want.

No. In general, auto_ptr is the most useful of the smart
pointers readily available.

> It might be though that what you want is not a smart pointer
> but a scope guard:

> template < typename T >
> struct heap_scope_guard // just does heap memory protection
> {
> explicit heap_scope_guard(T * t) : resource(t), released(false) {}
> ~heap_scope_guard() { if (!released) delete resource; }
> void release() { released = true; }
> private:
> T * resource;
> bool released;
> };

> Your code would then be:

> void new_call (Msg& msg)
> {
> Call * call_ptr;
> heap_scope_guard<Call> guard(call_ptr);
> CallList::add (call_ptr);
> guard.release();
> call_ptr->process_msg (msg);
> }

> You could add more, change a few things the way you want.
> Technically this would be the "correct" way to do what you
> want as the auto_ptr is actually providing more functionality
> than you actually need/want.

One could argue that. Adding something like release to scope
guard might be confusing to someone familiar with the concept.
And by using auto_ptr, you reserve the right to call a factory
function (which returns an auto_ptr): the semantics of auto_ptr
are, IMHO, perfect for this case.

--
James Kanze

James Kanze

unread,
Jan 7, 2010, 4:47:57 PM1/7/10
to
On Dec 11 2009, 6:45 pm, Paavo Helde <myfirstn...@osa.pri.ee> wrote:
> Nick Keighley <nick_keighley_nos...@hotmail.com> wrote in news:81377349-
> fdb9-4d2f-9852-c2b2a3bc1...@j14g2000yqm.googlegroups.com:

> > I wanted my code to look something like this

> > void new_call (Msg& msg)
> > {
> > smart_ptr<Call> call_ptr ();
> > CallList::add (*call_ptr); // may throw
> > Call *call = call.release();
> > call.process_msg (msg);
> > }

> > now that may not be quite right, but the aim was to allocate
> > a Call and store it in CallList. If CallList throws the
> > smart_ptr will destroy the Call, otherwise process the
> > message and the call remains in the CallList for more
> > message processing.

> > smart_ptr would not allow copy or assignment. Release
> > returns the pointer value and zeros its record. I was going
> > to call it ExplicitReleasePointer. But then I thought,surely
> > boost have already done this. Aha! scoped_ptr! Oops no. No
> > release(). The rationale for this is that scoped_ptr implies
> > no transfer of ownership. But I want to transfer ownership.
> > That I should use auto_ptr if I want transfer of ownership
> > semantics. But how do I coerce auto_ptr into doing the
> > cleanup. Should I be making my container class do the
> > cleanup? Or should I be using shared_ptr in both the
> > container class and my calling function?

> If I understand correctly, then you want something like
> ScopeGuard (look it up):

Actually, I think what he wants is auto_ptr. At least, it has
exactly the semantics he seems to require.

> #include <ScopeGuard/ScopeGuard.h>
>
> template <class T> struct Delete {
> void operator()(T *t) const { delete t;}
> };

> void new_call (Msg& msg)
> {
> Call* call_ptr = new Call();
> // assume ownership
> ScopeGuard guard = MakeGuard( Delete<Call>(), call_ptr);

> // pass object to container, container will assume
> // ownership iff the call does not throw.
> CallList::add(call_ptr); // may throw

> // give up my ownership
> guard.Dismiss();

> // call a method on the object owned by the container
> call_ptr->process_msg (msg);
> }

That looks to me to be more hassle than it's worth. And if he
ever decides that he needs a factory function, which will return
an auto_ptr, then the above becomes even more complicated.

> > I suppose the logic is that ownership is shared so you need
> > a shared pointer.

> Yes, a cleaner way would be to use boost::shared_ptr both in
> the container and in the caller function.

If the ownership really is shared, yes. But from what he's
explained so far, I don't think it is, and a shared_ptr would
not have the desired semantics.

--
James Kanze

0 new messages