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?
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.