two bases with shared_from_this?

Discussion in 'C++' started by limcore@gazeta.pl, Mar 6, 2007.

  1. Guest

    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




    --
    LimCore
    ---> oo
    Linux, Windows; Wysokopoziomowe C++, std, boost
    http://www.limcore.pl - w przygotowaniu
    , Mar 6, 2007
    #1
    1. Advertising

  2. Piyo Guest

    wrote:
    >
    > #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!!
    Piyo, Mar 6, 2007
    #2
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. ! aaa
    Replies:
    1
    Views:
    1,031
    ! aaa
    May 28, 2004
  2. news

    Help with data bases

    news, Nov 14, 2003, in forum: HTML
    Replies:
    4
    Views:
    414
  3. Jim Fischer
    Replies:
    3
    Views:
    423
    Jim Fischer
    Jul 31, 2003
  4. Dave Theese

    Initialization of virtual bases

    Dave Theese, Aug 24, 2003, in forum: C++
    Replies:
    1
    Views:
    320
    John Harrison
    Aug 24, 2003
  5. Lakrom

    To work with two data bases in asp

    Lakrom, Sep 1, 2005, in forum: ASP General
    Replies:
    1
    Views:
    98
    Aaron Bertrand [SQL Server MVP]
    Sep 1, 2005
Loading...

Share This Page