By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,677 Members | 1,237 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,677 IT Pros & Developers. It's quick & easy.

boost::shared_ptr and conversion to base class

P: n/a
Hi all

Given

bool bResult;
shared_ptr<cSampleData> pNewData;
shared_ptr<cBase> pNewBase;

where cSampleData is descended from cBase, the following gives me a valid
pNewData to the correct type:

bResult = Input(INPORT_snapshot)->ReceiveNow(pNewBase);
pNewData = pNewBase;

This works fine, although the assignment conversion seems to be a bit
longwinded.

ReceiveNow is defined as:
bool ReceiveNow(shared_ptr<CBase> & pNewObject);

However, the compiler won't allow me to call the following, due to the
inability to initialize the reference parameter of ReceiveNow:
bResult = Input(INPORT_snapshot)->ReceiveNow(pNewData);

Adding a cast compiles correctly:
bResult =
Input(INPORT_snapshot)->ReceiveNow(boost::dynamic_pointer_cast<CBase>(pNe wDa
ta));

but the pNewData is null afterwards.

Is there any way of passing the pointer to the derived type (pNewData) to
the function expecting a base class pointer in a single function call?

Is the shared_ptr getting confused by the dynamic_pointer_cast and deleting
the object incorrectly? Do I need to use a weak_ptr?

Any suggestions?

Thanks!

Ryan


Jul 22 '05 #1
Share this Question
Share on Google+
6 Replies


P: n/a
Ryan Mitchley <rm******@removethis.worldonline.co.za> wrote:
bool bResult;
shared_ptr<cSampleData> pNewData;
shared_ptr<cBase> pNewBase;

where cSampleData is descended from cBase, the following gives me a valid
pNewData to the correct type:

bResult = Input(INPORT_snapshot)->ReceiveNow(pNewBase);
pNewData = pNewBase;
The last line must not compile as you are trying to assign a pointer to base to a pointer to derived what essentially is a downcast. There is no implicit downcast in C++, so you must use appropriate form of xxx_cast<>.
This works fine, although the assignment conversion seems to be a bit
longwinded.

ReceiveNow is defined as:
bool ReceiveNow(shared_ptr<CBase> & pNewObject);
I assume CBase here and cBase above refer the same type.
However, the compiler won't allow me to call the following, due to the
inability to initialize the reference parameter of ReceiveNow:
bResult = Input(INPORT_snapshot)->ReceiveNow(pNewData);

Adding a cast compiles correctly:
bResult =
Input(INPORT_snapshot)->ReceiveNow(boost::dynamic_pointer_cast<CBase>(pNe wDa
ta));

but the pNewData is null afterwards.
Neither ReceiveNow(pNewBase) nor ReceiveNow(dynamic_pointer_cast<CBase>(pNewBase)) should compile. The reason is that ReceiveNow() function takes a non-const reference. In both cases you are tring to feed the function with an r-value. Non-const reference can not be bound to r-value (microsoft compilers allow to do that).

1) ReceiveNow(pNewBase) - although cBase and cSampleData types have an inheritance relationship, shared_ptr<cSampleData> and shared_ptr<cBase> are distinct unrelated types. There exists an implicit user defined conversion from shared_ptr<U> to shared_ptr<T> when U is convertible to T. That conversion yields an r-value that can not be bound to non-const reference.

2) boost::dynamic_pointer_cast<> returns its result by value which is an r-value and can not be bound to non-const reference.
Is there any way of passing the pointer to the derived type (pNewData) to
the function expecting a base class pointer in a single function call?


Make the function take a const reference, like ReceiveNow(shared_ptr<CBase> const& pNewObject). Or better make it take a reference to CBase, like ReceiveNow(CBase& pNewObject) and dereference a pointer before a call, like ReceiveNow(*pNewBase). In the latter case you avoid some obscurity and overhead related to shared_ptr<> conversions and the function becomes more generic as it does not depend on whatever (smart) pointers you use.

--
Maxim Yegorushkin
Jul 22 '05 #2

P: n/a
Hi Maxim

You wrote on Fri, 25 Jun 2004 11:43:05 +0400:

??>> bool bResult;
??>> shared_ptr<cSampleData> pNewData;
??>> shared_ptr<cBase> pNewBase;
??>>
??>> where cSampleData is descended from cBase, the following gives me a
??>> valid pNewData to the correct type: bResult =
??>> Input(INPORT_snapshot)->ReceiveNow(pNewBase); pNewData = pNewBase;

MY> The last line must not compile as you are trying to assign a pointer to
MY> base to a pointer to derived what essentially is a downcast. There is
MY> no implicit downcast in C++, so you must use appropriate form of
MY> xxx_cast<>.

Erm, it *does* compile fine using the Intel C++ Compiler 8.0. Maybe the
Boost library is doing the conversion...?

??>> This works fine, although the assignment conversion seems to be a bit
??>> longwinded.
??>>
??>> ReceiveNow is defined as:
??>> bool ReceiveNow(shared_ptr<CBase> & pNewObject);

MY> I assume CBase here and cBase above refer the same type.

Yes, sorry - typo.

??>> However, the compiler won't allow me to call the following, due to the
??>> inability to initialize the reference parameter of ReceiveNow:
??>> bResult = Input(INPORT_snapshot)->ReceiveNow(pNewData);
??>>
??>> Adding a cast compiles correctly:
??>> bResult =
??>> Input(INPORT_snapshot)->ReceiveNow(boost::dynamic_pointer_cast<CBase>(
??>> pNewDa ta)); but the pNewData is null afterwards.

MY> Neither ReceiveNow(pNewBase) nor
MY> ReceiveNow(dynamic_pointer_cast<CBase>(pNewBase)) should compile.

The first line doesn't compile, while the second does, without warnings.
Unfortunately, pNewBase is null after the call (even though ReceiveNow is
definitely returning a valid object).

MY> Make the function take a const reference, like
MY> ReceiveNow(shared_ptr<CBase> const& pNewObject).

Okay, I don't think this could work, as the ReceiveNow function needs to
update pNewObject with the object that has just been received... It's not
const - that's why it really needs to be pass by (non-const) reference.

MY> Or better make it take a reference to CBase, like ReceiveNow(CBase&
MY> pNewObject) and dereference a pointer before a call, like
MY> ReceiveNow(*pNewBase). In the latter case you avoid some obscurity and
MY> overhead related to shared_ptr<> conversions and the function becomes
MY> more generic as it does not depend on whatever (smart) pointers you
MY> use.

Unfortunately, the ReceiveNow function needs to be able to return a null
result (in pNewObject), since it is possible for nothing to be received.

Thanks for your time.

Ryan
Jul 22 '05 #3

P: n/a
Ryan Mitchley <rm******@removethis.worldonline.co.za> wrote:

??>> bool bResult;
??>> shared_ptr<cSampleData> pNewData;
??>> shared_ptr<cBase> pNewBase;
??>>
??>> where cSampleData is descended from cBase, the following gives me a
??>> valid pNewData to the correct type: bResult =
??>> Input(INPORT_snapshot)->ReceiveNow(pNewBase); pNewData = pNewBase;

MY> The last line must not compile as you are trying to assign a pointer to
MY> base to a pointer to derived what essentially is a downcast. There is
MY> no implicit downcast in C++, so you must use appropriate form of
MY> xxx_cast<>.

Erm, it *does* compile fine using the Intel C++ Compiler 8.0. Maybe the
Boost library is doing the conversion...?
Well, now I seem to remember that there was a discussion on this subject in boost newsgroup. But I could not find it, shame on me...

I tried the code on gcc 2.96 - it does not compile with correct diagnostic:

boost::shared_ptr<T>& boost::shared_ptr<T>::operator= (const boost::shared_ptr<Y> &) [with Y = base, T = derived]':
experiment.cpp:14: instantiated from here
/home/my/lib/boost/boost/shared_ptr.hpp:212: cannot convert `base *const' to `derived *' in assignment
??>> However, the compiler won't allow me to call the following, due to the
??>> inability to initialize the reference parameter of ReceiveNow:
??>> bResult = Input(INPORT_snapshot)->ReceiveNow(pNewData);
??>>
??>> Adding a cast compiles correctly:
??>> bResult =
??>> Input(INPORT_snapshot)->ReceiveNow(boost::dynamic_pointer_cast<CBase>(
??>> pNewDa ta)); but the pNewData is null afterwards.

MY> Neither ReceiveNow(pNewBase) nor
MY> ReceiveNow(dynamic_pointer_cast<CBase>(pNewBase)) should compile.

The first line doesn't compile, while the second does, without warnings.
Unfortunately, pNewBase is null after the call (even though ReceiveNow is
definitely returning a valid object).
That is because dynamic_pointer_cast<> returns a temporary (r-value) which gets bound to a *non-const* reference (which must not compile) to which you assign a new value inside your ReceiveNow() and then that temporary is destroyed right after the full expression has been executed. Stroustrup wrote in his CPPPL that that was the reason why it was prohibited to bind temporaries (r-values) to non-const references.
MY> Make the function take a const reference, like
MY> ReceiveNow(shared_ptr<CBase> const& pNewObject).

Okay, I don't think this could work, as the ReceiveNow function needs to
update pNewObject with the object that has just been received... It's not
const - that's why it really needs to be pass by (non-const) reference.
[]
Unfortunately, the ReceiveNow function needs to be able to return a null
result (in pNewObject), since it is possible for nothing to be received.


Why can't you make the function to return a pointer to a new object or zero pointer if there is none like:

shared_ptr<CBase> ReceiveNow(shared_ptr<CBase> const&);

and then call it like:

if(shared_ptr<CBase> new_object = ReceiveNow(pNewBase))
{
// new_object refers the new object here
}
else
{
// no new object received
}

--
Maxim Yegorushkin
Jul 22 '05 #4

P: n/a
Hi Maxim

Thanks for you reply, once again!

You wrote on Fri, 25 Jun 2004 17:06:40 +0400:

??>> Erm, it *does* compile fine using the Intel C++ Compiler 8.0. Maybe
??>> the Boost library is doing the conversion...?

MY> Well, now I seem to remember that there was a discussion on this
MY> subject in boost newsgroup. But I could not find it, shame on me...

MY> I tried the code on gcc 2.96 - it does not compile with correct
MY> diagnostic:

That's strange - I was kind of under the impression that the Intel C++
Compiler was a relatively strict compiler . . . I suppose that the
requirement for compatibility with MS Visual C++ necessitates some
relaxation of the strictness! Possibly there are some compiler flags that
will affect this behaviour . . .

MY> Why can't you make the function to return a pointer to a new object or
MY> zero pointer if there is none like:

MY> shared_ptr<CBase> ReceiveNow(shared_ptr<CBase> const&);

MY> and then call it like:

Okay - this is pretty much what I've done, successfully, except that it ends
up being even simpler:
shared_ptr<CBase> ReceiveNow();

I can now successfully call
shared_ptr<cSampleData> pNewData = Input(INPORT_snapshot)->ReceiveNow();

I'm curious, though, why this pointer assignment of two different types
works in the return value, but the pass by reference (function parameter)
didn't work . . .

Ryan
Jul 22 '05 #5

P: n/a
On Thu, 24 Jun 2004 16:50:08 +0200, "Ryan Mitchley"
<rm******@removethis.worldonline.co.za> wrote:
Hi all

Given

bool bResult;
shared_ptr<cSampleData> pNewData;
shared_ptr<cBase> pNewBase;

where cSampleData is descended from cBase, the following gives me a valid
pNewData to the correct type:

bResult = Input(INPORT_snapshot)->ReceiveNow(pNewBase);
pNewData = pNewBase;
The second line should require a dynamic_pointer_cast.
This works fine, although the assignment conversion seems to be a bit
longwinded.

ReceiveNow is defined as:
bool ReceiveNow(shared_ptr<CBase> & pNewObject);

However, the compiler won't allow me to call the following, due to the
inability to initialize the reference parameter of ReceiveNow:
bResult = Input(INPORT_snapshot)->ReceiveNow(pNewData);
Yes, of course not, since ReceiveNow could assign a cAnotherClass to
the pointer, and then you'd have a cSampleData pointer pointing to an
unrelated class. Similarly:

bool ReceiveNow(CBase*& oNewObject);
cSampleData* ptr;
ReceiveNow(ptr);

also won't work, for the same reason (technically, you can't bind a
non-const reference to an rvalue).

Adding a cast compiles correctly:
bResult =
Input(INPORT_snapshot)->ReceiveNow(boost::dynamic_pointer_cast<CBase>(pNe wDa
ta));

but the pNewData is null afterwards.
I'm very surprised the above makes any difference. I would assume that
the cast would return an rvalue, so if it compiles, your compiler is
broken.
Is there any way of passing the pointer to the derived type (pNewData) to
the function expecting a base class pointer in a single function call?
No, since such a think breaks the contract of your ReceiveNow
function.
Is the shared_ptr getting confused by the dynamic_pointer_cast and deleting
the object incorrectly? Do I need to use a weak_ptr?

Any suggestions?


The two step process is the correct way to do it. Or if ReceiveNow
really returns some cSampleData, you should update the interface to
take a shared_ptr<cSampleData>&.

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #6

P: n/a
"Ryan Mitchley" <rm******@removethis.worldonline.co.za> wrote in message news:

[]
shared_ptr<CBase> ReceiveNow();

I can now successfully call
shared_ptr<cSampleData> pNewData = Input(INPORT_snapshot)->ReceiveNow();

I'm curious, though, why this pointer assignment of two different types
works in the return value, but the pass by reference (function parameter)
didn't work . . .


Intel C++ compiler by default lets one assign a pointer to base to a
pointer to derived.

struct B {};
struct D : B {};

int main()
{
D* d;
B* b;
d = b;
}

produces only:

warning #556: a value of type "B *" cannot be assigned to an entity of
type "D *"
d = b;
^

It is possible to make this warning an error.
Jul 22 '05 #7

This discussion thread is closed

Replies have been disabled for this discussion.