473,406 Members | 2,336 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

boost::shared_ptr and conversion to base class

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
6 9007
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
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
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
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
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
"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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Philippe Guglielmetti | last post by:
I just ported old (VC6) working code to VC7.1 and have trouble with something like: class A; // forward typedef boost::smart_ptr<A> Aptr; class B{ Aptr a; virtual ~B(); // implemented...
5
by: ctick | last post by:
Are there any advantages of using boost::shared_ptr other than auto_ptr from standard library?
2
by: krema2ren | last post by:
Hi I've the following header problem that I need two classes to know each other through a boost::shared_ptr. Does any of you smart guys have a solution? A.h ---------------------- #include...
6
by: Toby Bradshaw | last post by:
Hi, Consider the following: class A { public: virtual bool foo() = 0; };
2
by: ketan | last post by:
Hi, While reading the Boost::shared_ptr implementation, I came across this method template<class Tclass shared_ptr { ..... template<class Y> shared_ptr(shared_ptr<Yconst & r,...
1
by: rssmps | last post by:
Hi, first post and here it goes... This is the current code (working) that I have. It works but for large number of A & B objects, it's not the most efficient. It's also not really heterogenous...
9
by: Christopher | last post by:
If a method is declared to return a type boost::shared_ptr<sometype>, how can the method be changed to do the equivalent of returning NULL when it was declared to return a raw pointer?
4
by: EnsGabe | last post by:
Suppose you have a class heirarchy as such: class Base{ .... }; class Mid1 : public Base{ ....
0
by: phlip | last post by:
Nick Keighley wrote: CC'd to the correct newsgroup. Yes, the destructor of the shared pointer will delete the object. Then its former address will convert to a reference. At some point -...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.