two bases with shared_from_this?

L

limcore

How to solve following problem:


A1 A2 - two parents, they must have enable_shared_from_this
| |
| |
\ /
B - B class
|
C - C class


now in C I need to get pointer to this as shared_ptr<A1>
and later I need to dynamic cast it into shared_ptr<C>


I tried several times with but the code doesnt work.


Two examples with resuls below

============================================================

One of the attempts, introducing additional base class which is base of
A1 and A2.

#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

using namespace std;
using namespace boost;

struct cWithSharedThis : enable_shared_from_this<cWithSharedThis> {
cWithSharedThis() {
cout << "cWithSharedThis() " << (void*)this << endl;
}
};

struct cA1 : public virtual cWithSharedThis {
string name;
cA1(string n) : name(n) {
cout << "cA1 I am this " << (void*)this << endl;
}
virtual ~cA1() {}
virtual void Hello() { cout<<"I am " << name << " type " << Type()
<< endl; }
virtual string Type() { return "cA1"; }
virtual void foo() { cout<<"Foo 1 nothing"<<endl; }
} ;

struct cA2 : public virtual cWithSharedThis {
string name;
cA2(string n) : name(n) {
cout << "cA2 I am this " << (void*)this << endl;
}
virtual ~cA2() {}
virtual void Hello() { cout<<"I am " << name << " type " << Type()
<< endl; }
virtual string Type() { return "cA2"; }
virtual void foo() { cout<<"Foo 2 nothing"<<endl; }
} ;

struct cB : public cA1, public cA2 {
cB(string n):cA1(n+"1"),cA2(n+"2"){
cout << "cB I am this " << (void*)this << endl;
}
virtual string Type() { return "cB"; }
};

struct cC : public cB {
cC(string n):cB(n) {
cout << "cC I am this " << (void*)this << endl;
}
virtual string Type() { return "cC"; }
virtual void foo() {
cout << "foo() I am this " << (void*)this << endl;
shared_ptr<cWithSharedThis> ptr_base_this =
cA1::shared_from_this(); // <------
if (!ptr_base_this) { cout << "ptr_base_this is NULL! " << endl
<< flush; return; }
cout << "We got ptr_base_this in " << (void*)ptr_base_this.get()
<< endl << flush;
shared_ptr<cA1> ptr = dynamic_pointer_cast<cA1>(ptr);
cout << "We got ptr in " << (void*)ptr.get() << endl << flush;
if (!ptr) { cout << "ptr is NULL! " << endl << flush; return; }
ptr->Hello();
}
};

int main() {
shared_ptr<cC> c( new cC("xxx") );
c->foo();
}




g++ x.cpp -o x.elf -g3 -O0 -Wall
../x.elf
cWithSharedThis() 0x804c308
cA1 I am this 0x804c2f8
cA2 I am this 0x804c300
cB I am this 0x804c2f8
cC I am this 0x804c2f8
foo() I am this 0x804c2f8
We got ptr_base_this in 0x804c308
make: *** [run] Segmentation fault

============================================================


second example



#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

using namespace std;
using namespace boost;

struct cA1 : enable_shared_from_this<cA1> {
string name;
cA1(string n) : name(n) {}
virtual ~cA1() {}
virtual void Hello() { cout<<"I am " << name << " type " << Type()
<< endl; }
virtual string Type() { return "cA1"; }
virtual void foo() { cout<<"Foo 1 nothing"<<endl; }
} ;

struct cA2 : enable_shared_from_this<cA2> {
string name;
cA2(string n) : name(n) {}
virtual ~cA2() {}
virtual void Hello() { cout<<"I am " << name << " type " << Type()
<< endl; }
virtual string Type() { return "cA2"; }
virtual void foo() { cout<<"Foo 2 nothing"<<endl; }
} ;

struct cB : public cA1, public cA2 {
cB(string n):cA1(n+"1"),cA2(n+"2"){}
virtual string Type() { return "cB"; }
};

struct cC : public cB {
cC(string n):cB(n) {}
virtual string Type() { return "cC"; }
virtual void foo() {
shared_ptr<cA1> ptr = cA1::shared_from_this(); // <------
ptr->Hello();
}
};

int main() {
shared_ptr<cC> c( new cC("xxx") );
c->foo();
}





terminate called after throwing an instance of 'boost::bad_weak_ptr'
what(): boost::bad_weak_ptr
Aborted
 
P

Piyo

#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

using namespace std;
using namespace boost;

struct cA1 : enable_shared_from_this<cA1> {
string name;
cA1(string n) : name(n) {}
virtual ~cA1() {}
virtual void Hello() { cout<<"I am " << name << " type " << Type()
<< endl; }
virtual string Type() { return "cA1"; }
virtual void foo() { cout<<"Foo 1 nothing"<<endl; }
} ;

struct cA2 : enable_shared_from_this<cA2> {
string name;
cA2(string n) : name(n) {}
virtual ~cA2() {}
virtual void Hello() { cout<<"I am " << name << " type " << Type()
<< endl; }
virtual string Type() { return "cA2"; }
virtual void foo() { cout<<"Foo 2 nothing"<<endl; }
} ;

struct cB : public cA1, public cA2 {
cB(string n):cA1(n+"1"),cA2(n+"2"){}
virtual string Type() { return "cB"; }
};

struct cC : public cB {
cC(string n):cB(n) {}
virtual string Type() { return "cC"; }
virtual void foo() {
shared_ptr<cA1> ptr = cA1::shared_from_this(); // <------
ptr->Hello();
}
};

int main() {
shared_ptr<cC> c( new cC("xxx") );
c->foo();
}

I decided to use your second example since it is straightforward to
see what is going on. Unfortunately, my conclusion is you will
ultimately have to solve this through rearchitecting your class
hierarchy based on what I uncovered. (ie. I don't know how to
directly solve your problem since I do not know your requirements)

So here is what I tried:
Using gcc344 and boost 1.33.1, I compared a trace of the program
when cC just derived from enable_shared_from_this and how you
wrote it. The main difference that I saw is this. When it was working,
(ie. when cC just derived from enable_shared_from_this directly),
the object construction went to shared_ptr.hpp:86. This then triggered
proper _internal_weak_pointer construction. In your second example,
weirdly enough, it went to shared_ptr.hpp:91. If you look at the
difference, one will trigger proper counting, whereas the other has
an empty body!! This is what is causing you to get the throw.

Now why exactly is this happening. I couldn't directly figure this out
but I decided to use gc402 tr1 memory and substituted their shared
pointer in your example. Here is what I got:

main.cpp:52: instantiated from here
/opt/gcc402/lib/gcc/i686-pc-linux-gnu/4.0.2/../../../../include/c++/4.0.2/tr1/boost_shared_ptr.h:499:
error: call of overloaded
‘__enable_shared_from_this(std::tr1::shared_count&, cC*&, cC*&)’ is
ambiguous
/opt/gcc402/lib/gcc/i686-pc-linux-gnu/4.0.2/../../../../include/c++/4.0.2/tr1/boost_shared_ptr.h:461:
note: candidates are: void std::tr1::__enable_shared_from_this(const
std::tr1::shared_count&, ...)
/opt/gcc402/lib/gcc/i686-pc-linux-gnu/4.0.2/../../../../include/c++/4.0.2/tr1/boost_shared_ptr.h:946:
note: void std::tr1::__enable_shared_from_this(const
std::tr1::shared_count&, const std::tr1::enable_shared_from_this<_Tp>*,
const _Tp1*) [with _Tp1 = cC, _Tp = cA1]
/opt/gcc402/lib/gcc/i686-pc-linux-gnu/4.0.2/../../../../include/c++/4.0.2/tr1/boost_shared_ptr.h:946:
note: void std::tr1::__enable_shared_from_this(const
std::tr1::shared_count&, const std::tr1::enable_shared_from_this<_Tp>*,
const _Tp1*) [with _Tp1 = cC, _Tp = cA2]

Now, the implementations of tr1/memory and boost is not identical but
similar enough to probably point out the problem you are encountering.
Basically, what this error is telling me is that shared_ptr internally
is confused as to how to construct the weak pointer since there are
two of them that are viable. I am guessing that in boost 1.33.1, the
confusion is eliminated by inserting shared_ptr.hpp:91 BUT this causes
major problems.


Here are two suggestions: (a) preferred (b) if you have no alternative

a) Use intrusive pointers instead. Since the count and counting
mechanism is controlled by you the user and is embedded inside
your object instead. There is no requirement to use weak pointers
and there will be no ambiguity (by your proper design). Intrusive
pointers also can "get a ref counted pointer from itself" by virtue
of the fact that the count is embedded in the object.

Check out:

<boost/intrusive_ptr.hpp>

for more info on this.


b) in your constructors (such as for cC, cB or both) you will need
to perform manual proper construction of the weak pointer yourself.
Since you are deriving from this:
template<class T> class enable_shared_from_this
{
public:
[..snip..]
typedef T _internal_element_type; // for bcc 5.5.1
mutable weak_ptr<_internal_element_type> _internal_weak_this;
};

you can perform manual initialization of the public _internal_weak_this
pointer in your constructor. This will solve your problems also but I
honestly think it is quite dangerous/tedious to do so.

HTH!!
 

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,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top