Search code examples
c++boostshared-ptr

Constructor overloading with boost::shared_ptr


Consider the following .h file:

#ifndef COM_H_
#define COM_H_

#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <map>

class B;

class A : public boost::enable_shared_from_this<A>{
public:
    A(){}
    ~A(){}

    void Init();

    boost::shared_ptr<B> b_ptr_;
};

class B : public boost::enable_shared_from_this<B>{
public:

    B(){}
    B(boost::shared_ptr<A> a_ptr);
    B(int j, boost::shared_ptr<A> a_ptr);
    ~B(){}

    void Init();
    void Init(boost::shared_ptr<A> a_ptr);
    void Init(int j, boost::shared_ptr<A> a_ptr);

    std::string b;
    boost::shared_ptr<A> a_ptr_;
};
#endif /* COM_H_ */

and the .cc file:

#include "com.h"

void A::Init() {

    // Case 1 not working
    // boost::shared_ptr<B> b1(new B(shared_from_this()));
    // b1->Init();

    // Case 2 working
    boost::shared_ptr<B> b2(new B());
    b2->Init(shared_from_this());
}

B::B(boost::shared_ptr<A> a_ptr) {
    B(2, a_ptr);
}

B::B(int j, boost::shared_ptr<A> a_ptr) {
    a_ptr_ = a_ptr;
    b = "b";
}

void B::Init() {
    a_ptr_->b_ptr_ = shared_from_this();
}

void B::Init(boost::shared_ptr<A> a_ptr) {
    Init(2, a_ptr);
}

void B::Init(int j, boost::shared_ptr<A> a_ptr) {

    a_ptr_ = a_ptr;
    b = "b";
    a_ptr_->b_ptr_ = shared_from_this();
}

In main:

#include "com.h"
#include <iostream>
int main() {

    boost::shared_ptr<A> a(new A());
    a->Init();

    std::cout << a->b_ptr_->b << std::endl;

    return 0;
}

When passing a boost::shared_ptr to a constructor and then calling another (overloaded) constructor with the same pointer as argument, the object pointed by the shared_ptr is lost and the error

terminate called after throwing an instance of 'boost::exception_detail::clone_impl

' what(): tr1::bad_weak_ptr

is thrown. The same does not happen when calling two overloaded functions (Init) in the same fashion.

Can anyone please explain it?


Solution

  • The problem is that you are calling shared_from_this() during B's construction, which is forbidden because the shared pointer to B hasn't been initialized at that time.

    Specifically, this constructor is the one you're calling:

    B::B(boost::shared_ptr<A> a_ptr) {
        Init(2, a_ptr);  // runtime error -- Init(...) calls shared_from_this!
    }
    

    Answer Part 2:

    I suspect you're used to another language :) In C++ you cannot call another constructor in the way you are trying to do. The line

    B(2, a_ptr);
    

    is not doing what you think -- all it's doing is constructing a temporary B object which is immediately destroyed. It won't call the other constructor. So you're ending up with a B that still has a default constructed a_ptr_ member.

    C++-11, if your compiler supports it, has delegating constructors, which would look like this:

    B(shared_ptr<A> a_ptr) : B(2, a_ptr) {...}
    

    ... Otherwise you have to declare another function and have both constructors call it.