which pointer

N

Nick Keighley

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

Victor Bazarov

Nick said:
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
 
J

James Kanze

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

Nick Keighley

NickKeighleywrote:


Declared a function.


Dereferenced a function???


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


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



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



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


Probably.  The ownership transfer is automatic then.

ok, thanks
"with the something with the"?

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

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.

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

I was attempting that.
 
N

Nick Keighley

On Dec 11, 3:58 pm, NickKeighley<[email protected]>
wrote:

no, see my earlier 2010 post.

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.


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


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

James Kanze

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?
well, generally call the dtor
this sounds exactly what I want.

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.

[...]
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.
or a pointer

But the semantics of containing a pointer and containing an
object are radically different. Which semantics do you want?
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?
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".
 
N

Noah Roberts

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

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

James Kanze

@m26g2000yqb.googlegroups.com>, (e-mail address removed) says...

[...]
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.
 
J

James Kanze

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

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,154
Messages
2,570,870
Members
47,400
Latest member
FloridaFvt

Latest Threads

Top