Downcast with smart pointers?

A

alebcn75

Hello,

I'm having a design issue that I can't solve. I'm getting from a
network a stream of data, which is a http message (my program is
neither a client or server, it just catches messages over the network)

For this I have a class http_message with the usual methods (to access
header, fields, etc)
I also have two other classes, http_request and http_response, which
should be used depending on the type of message received. These two
classes derive from http_message, and contain some more helper
methods. They don't have any data (as it uses the data from the base
class)

And this is my problem. At some point I'd like to instantiate a
request or response data, but I don't know how to do it, as I'm using
smart pointers instead of plain pointers (the program uses several
threads, and these objects are accessed by many of them)

If I were using simple pointers, I'd do a dynamic_cast, but how is
this done with a smart pointer? (I'm using the CountedPtr available in
many places) I thought about using a copy constructor in the request
and response classes, taking a message as parameter, and initializing
the object from there, but that doesn't look very well, does it?

Any comment about how to proceed in this case? Any advice/example will
be greatly appreciated.

Thanks.
 
K

kwikius

Hello,

I'm having a design issue that I can't solve. I'm getting from a
network a stream of data, which is a http message (my program is
neither a client or server, it just catches messages over the network)

For this I have a class http_message with the usual methods (to access
header, fields, etc)
I also have two other classes, http_request and http_response, which
should be used depending on the type of message received. These two
classes derive from http_message, and contain some more helper
methods. They don't have any data (as it uses the data from the base
class)

And this is my problem. At some point I'd like to instantiate a
request or response data, but I don't know how to do it, as I'm using
smart pointers instead of plain pointers (the program uses several
threads, and these objects are accessed by many of them)

If I were using simple pointers, I'd do a dynamic_cast, but how is
this done with a smart pointer? (I'm using the CountedPtr available in
many places) I thought about using a copy constructor in the request
and response classes, taking a message as parameter, and initializing
the object from there, but that doesn't look very well, does it?

Any comment about how to proceed in this case? Any advice/example will
be greatly appreciated.

Thanks.

Smart pointers usually come with some downcasting mechanism with
similar functionality to dynamic_cast. So check the documentation. If
yours doesnt have this facility then its seriously worth trying to
move to one that does, as its a pretty basic functionality requirement
for smart pointers.

regards
Andy little
 
B

BobR

And this is my problem. At some point I'd like to instantiate a
request or response data, but I don't know how to do it, as I'm using
smart pointers instead of plain pointers....

What good is a 'smart_pointer' (or any pointer) if you can't get at what it
points to?
If I were using simple pointers, I'd do a dynamic_cast, but how is
this done with a smart pointer?

Show what you have tried (and the first 3 errors if it didn't compile).

Alf P. Steinbach's "Pointers" document:
http://home.no.net/dubjai/win32cpptut/special/pointers/ch_01.pdf
 
A

alebcn75

Smart pointers usually come with some downcasting mechanism with
similar functionality to dynamic_cast. So check the documentation. If
yours doesnt have this facility then its seriously worth trying to
move to one that does, as its a pretty basic functionality requirement
for smart pointers.

regards
Andy little

Thank you for your answer. Unfortunately the implementation I use
doesn't provide downcasting. I took it from josuttis' book.
Could you recommend me some implementation that it does? I'd need it
to be public, as my code is meant to be portable (even in some
environments where std c++ is not available)

Thank you.
 
A

alebcn75

What good is a 'smart_pointer' (or any pointer) if you can't get at what it
points to?




Show what you have tried (and the first 3 errors if it didn't compile).

Alf P. Steinbach's "Pointers" document:http://home.no.net/dubjai/win32cpptut/special/pointers/ch_01.pdf

Hello, thanks for sharing that link, it looks like a nice book, I'll
give it a read.

The more I see this the more I think I'm not doing it "the right way"
May I ask you all what is the correct idiom (if there is just one..)
to do something like this?

I receive a byte stream from a network interface, so I instantiate a
generic message object:

SmartPtr<HttpMsg> msg(new HttpMsg(buffer));

When constructed, the class constructor parses the message
(generically) and then I have a message object, which is either a
request or a response (assuming there isn't any error). So here is my
problem then: given that some functionality only makes sense for
request or responses, I have to derive classes with some specific
methods:

class HttpRequest : public HttpMsg
{};

class HttpResponse : public HttMsg
{};

(Both derived classes contains only new methods, no data).

In some situations, I'd like to pass some of these objects to a
function, so assuming I have a generic function (because it could
either accept a request or response):

void foo(const SmartPtr<HttpMsg>& msg);

Then inside this function, I'd need to instantiate the correct object.
But how to do it? I tried:

SmartPtr<HttpResponse> resp = msg;

But of course doesn't work. If I were using normal pointers, then I'd
do dynamic_cast<HttpResponse*>(msg) and everything ok.

So it seems that the SmartPtr needs to support this, unless there is
some other way to achieve similar functionality. I'm also concerned
about the smart pointer behaviour, as I wouldn't want to trash its
internal data and miss the advantage of using them.

Is my "design" ok? Or maybe is some easier way I'm missing?

Any advice?
Thanks.
 
K

kwikius

On Jul 21, 11:55 pm, "BobR" <[email protected]> wrote:
void foo(const SmartPtr<HttpMsg>& msg);

OK. There is a wide number of flavours of smart pointer, but generally
speaking this is
the one entity that you don't really want to pass by reference.

The usual purpose of the smart pointer is that you want to keep the
object alive. Usually The only way that the smart pointer knows you
are using it is if you copy it. Passing by reference is done to avoid
copying, so the smart pointer won't be aware you are using it and may
therefore feel its quite OK to die, so this is the one entity that you
should always pass by value.
Then inside this function, I'd need to instantiate the correct object.
But how to do it? I tried:

SmartPtr<HttpResponse> resp = msg;

But of course doesn't work. If I were using normal pointers, then I'd
do dynamic_cast<HttpResponse*>(msg) and everything ok.

If you rolled your own smart pointer, you could just add some get()
function to get at the raw pointer and then dynamic_cast as usual.

Someone else on the list may be able to recommend a widely used smart
pointer...

regards
Andy Little
 
M

Ming

Hi,

Hello, thanks for sharing that link, it looks like a nice book, I'll
give it a read.

The more I see this the more I think I'm not doing it "the right way"
May I ask you all what is the correct idiom (if there is just one..)
to do something like this?

I receive a byte stream from a network interface, so I instantiate a
generic message object:

SmartPtr<HttpMsg> msg(new HttpMsg(buffer));

When constructed, the class constructor parses the message
(generically) and then I have a message object, which is either a
request or a response (assuming there isn't any error). So here is my
problem then: given that some functionality only makes sense for
request or responses, I have to derive classes with some specific
methods:

class HttpRequest : public HttpMsg
{};

class HttpResponse : public HttMsg
{};

(Both derived classes contains only new methods, no data).

In some situations, I'd like to pass some of these objects to a
function, so assuming I have a generic function (because it could
either accept a request or response):

void foo(const SmartPtr<HttpMsg>& msg);

Then inside this function, I'd need to instantiate the correct object.
But how to do it? I tried:

SmartPtr<HttpResponse> resp = msg;

But of course doesn't work. If I were using normal pointers, then I'd
do dynamic_cast<HttpResponse*>(msg) and everything ok.

It doesn't work because there is no implicit conversion from
SmartPtr<HttpMsg> to SmartPtr<HttpResponse>. One possible way to do it
is to create a derived class from the standard smart pointer (of
course, if you have control of the pointer implemetation, do it
directly on its implementation), and add

a member template function in the auto_ptr implementation, similar to
this

template <class NEW_T>
operator auto_ptr<NEW_T>
{
return auto_otr<NEW_T> (dynamic_cast (NEW_T *> (this->get ()));
}

or add a static template function called _narrow, which do

template <class NEW_T>
static my_auto_ptr<new_T> __narrow (my_auto_ptr<T> &p)
{
new_T *new_p = dynamic_cast<new_T *> (p.get());
return my_auto_ptr<new_T>(new_p);
}

and invoke the conversion like this

My_SmartPtr<HttpResponse> resp = My_SmartPtr<msg>::_narrow
<HttpResponse> (msg)


it should work theoritically, but i didn't try it. HTH
 
T

Thomas J. Gritzan

Hello, thanks for sharing that link, it looks like a nice book, I'll
give it a read.

The more I see this the more I think I'm not doing it "the right way"
May I ask you all what is the correct idiom (if there is just one..)
to do something like this?

I receive a byte stream from a network interface, so I instantiate a
generic message object:

SmartPtr<HttpMsg> msg(new HttpMsg(buffer));

When constructed, the class constructor parses the message
(generically) and then I have a message object, which is either a
request or a response (assuming there isn't any error). So here is my
problem then: given that some functionality only makes sense for
request or responses, I have to derive classes with some specific
methods:
[...]

"Once a HttpMsg..."

You can't change the type of an object. When you instantiate a HttpMsg, you
can't change the type to a HttpRequest or HttpResponse after that.

You can make a 'factory', a function that parses a buffer and gives you
either a HttpRequest or a HttpResponse:

SmartPtr<HttpMsg> createMessage(const std::string& buffer)
{
// ... parse buffer...
if (isRequest)
return SmartPtr<HttpMsg>(new HttpRequest(buffer));
else
In some situations, I'd like to pass some of these objects to a
function, so assuming I have a generic function (because it could
either accept a request or response):

void foo(const SmartPtr<HttpMsg>& msg);

Then inside this function, I'd need to instantiate the correct object.
But how to do it? I tried:

SmartPtr<HttpResponse> resp = msg;

But of course doesn't work. If I were using normal pointers, then I'd
do dynamic_cast<HttpResponse*>(msg) and everything ok.

Get the raw pointer and do a dynamic_cast. Or use another smart pointer
like boost::shared_ptr (which is tr1::shared_ptr), that has a dynamic_cast
replacement: dynamic_pointer_cast<>.

Well, smart pointers transfer ownership. If your foo() function here
doesn't store the HttpMsg object, it could take a const reference instead:

void foo(const HttpMsg& msg);
 
T

Thomas J. Gritzan

kwikius said:
OK. There is a wide number of flavours of smart pointer, but generally
speaking this is
the one entity that you don't really want to pass by reference.

The usual purpose of the smart pointer is that you want to keep the
object alive. Usually The only way that the smart pointer knows you
are using it is if you copy it. Passing by reference is done to avoid
copying, so the smart pointer won't be aware you are using it and may
therefore feel its quite OK to die, so this is the one entity that you
should always pass by value.

References are always bound to an object. So there must be another
SmartPtr<HttpMsg> somewhere, and that will keep the passed HttpMsg object
alive.
 
K

kwikius

kwikius schrieb:








References are always bound to an object. So there must be another
SmartPtr<HttpMsg> somewhere, and that will keep the passed HttpMsg object
alive.

I will leave that to the experts to comment out in a single threaded
program.

Quoting the OP...

"(the program uses several
threads, and these objects are accessed by many of them) ".

regards
Andy Little
 
K

kwikius

I will leave that to the experts to comment out in a single threaded
program.

Ooops.. That should have read "comment on" not comment out. I
sincerely apologise. I wasnt trying to be rude.

regards
Andy Little
 
A

alebcn75

void foo(const SmartPtr said:
OK. There is a wide number of flavours of smart pointer, but generally
speaking this is
the one entity that you don't really want to pass by reference.

The usual purpose of the smart pointer is that you want to keep the
object alive. Usually The only way that the smart pointer knows you
are using it is if you copy it. Passing by reference is done to avoid
copying, so the smart pointer won't be aware you are using it and may
therefore feel its quite OK to die, so this is the one entity that you
should always pass by value.

Thank you for that advice. My idea was passing by reference in some
cases, to avoid such copy, but thinking better, it's quite dangerous
to do (specially with multiple threads that could lead to race
conditions)
If you rolled your own smart pointer, you could just add some get()
function to get at the raw pointer and then dynamic_cast as usual.

Yes, I'm trying to do that by no luck so far (more on this later)

Thank you.
 
A

alebcn75

Hi,
It doesn't work because there is no implicit conversion from
SmartPtr<HttpMsg> to SmartPtr<HttpResponse>. One possible way to do it
is to create a derived class from the standard smart pointer (of
course, if you have control of the pointer implemetation, do it
directly on its implementation), and add

a member template function in the auto_ptr implementation, similar to
this

template <class NEW_T>
operator auto_ptr<NEW_T>
{
return auto_otr<NEW_T> (dynamic_cast (NEW_T *> (this->get ()));

}

Correct me if I wrong, but in that case I'd get two separate smart
pointers, wouldn't I? I'd prefer that both pointers share the
reference count, otherwise it could be very dangerous (if original
smart pointer's count reach zero, then pointer would be deleted)
Unless of course that I do a deep copy of the inner object, but that
wouldn't be performance wise..

This is what I've trying to do. I took the implementation from here,
which is simple enough and fits my purposes (at least it did before
getting here!)

http://www.josuttis.de/libbook/cont/countptr.hpp.html

And to add support for dynamic_cast I made some additions:

Added this friend function:

template<class U>
friend
CountedPtr<U> Dynamic_Cast(CountedPtr<T>& sp)
{
U* upcast = dynamic_cast<U*>(sp.ptr);

if (upcast)
return CountedPtr<U>(upcast, sp.count);
else
return CountedPtr<U>;
}

For this to work, I had to create a new constructor which not only
takes a pointer, but an already existing counter. This way, I avoid
what I mentioned you above.

Unfortunately, it doesn't work. I'm getting an error saying this
(using VC6)

none of the 7 overloads can convert parameter 1 from type 'const class
CountedPtr<class HttpMsg>'

Also, now I'm getting another surprise: If I have this method
void foo(const CountedPtr<HttpMsg> msg);

Then if I have an instance:
CountedPtr<HttpRequest> req(new HttpRequest);

Then I'd like to do this:
foo(req);

But it doesn't work either! Why is that? Shouldn't upcasting work?

Thanks again.
 
A

alebcn75

You can't change the type of an object. When you instantiate a HttpMsg, you
can't change the type to a HttpRequest or HttpResponse after that.

You can make a 'factory', a function that parses a buffer and gives you
either a HttpRequest or a HttpResponse:

SmartPtr<HttpMsg> createMessage(const std::string& buffer)
{
// ... parse buffer...
if (isRequest)
return SmartPtr<HttpMsg>(new HttpRequest(buffer));
else
return SmartPtr<HttpMsg>(new HttpResponse(buffer));

}

Yes, I'm doing this now to create the appropriate object. But my
problem is that I'm passing this to a method that takes either request
or responses, so its parameter is a HttpMsg. And now I'm having two
problems: neither upcasting nor downcasting seem to work!
Get the raw pointer and do a dynamic_cast. Or use another smart pointer
like boost::shared_ptr (which is tr1::shared_ptr), that has a dynamic_cast
replacement: dynamic_pointer_cast<>.

Yes, unfortunately I'd like to make my own, for simplicity purposes,
and for space. Also, some environments I use don't have std library
available.
Well, smart pointers transfer ownership. If your foo() function here
doesn't store the HttpMsg object, it could take a const reference instead:

void foo(const HttpMsg& msg);

That would be one option. I assume it is safe enough.. but my problem
is that these messages are passed from one side to another, including
different threads..

Thanks!
 
A

alebcn75

I will leave that to the experts to comment out in a single threaded
program.

Quoting the OP...

"(the program uses several
threads, and these objects are accessed by many of them) ".

regards
Andy Little

Yes, but for the moment, I'd feel happy if I made it work even for
single thread environments.

Thanks.
 
K

kwikius

Yes, but for the moment, I'd feel happy if I made it work even for
single thread environments.

I would recommend you get hold of a library with std::tr1::shared_ptr
for your compiler. It will be in the next C++ standard.
I don't know however where you can get such a library.. Only info I
can find is:

http://www.amazon.com/Standard-Library-Extensions-Tutorial-Reference/dp/0321412990

Point is that smart pointers are tricky to get right, so before
rolling your own see what the current solutions are. There is a long
history of smart pointers and no perfect solution and many many subtle
problems.

(Someone may want to hint very similar lib to std::tr1::shared_ptr . I
aint going to though ;-))

regards
Andy Little
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top