Ricardo Capurro wrote:
Hello,
We are really very happy and impressed with boost's smart_pointers, and we found the section "Smart Pointer Programming Techniques" (http://www.boost.org/libs/smart_ptr/sp_techniques.html) in boost smart_pointer documentation very useful, but we are having this problem:
We have two classes X and Y, and each object of class X holds an object of class Y, and we need to implement a method in class X to get a shared_ptr<Y> so we can access Y instance inside X, and we need that X objects (that are too referenced by shared_ptr<X>) don't be deleted until all references to the Y object are destroyed. See the problem in this code:
class Y {};
class X : public enable_shared_from_this<X> {
Y y;
public:
shared_ptr<Y> ptr_y(); // Oops, how do we do here???
};
Our first approach was "Using a shared_ptr to hold a pointer to a statically allocated object" (http://www.boost.org/libs/smart_ptr/sp_techniques.html#static), but this doesn't work because X objects can be destroyed and we still have pointers to contained Y object, so we try a custom deletor like this:
[as in #another_sp]
And now the problem was resolved but with one little drawback, we are not sharing the same counter between shared_ptr<X> and shared_ptr<Y>, so start looking boost's code to shange it in a way that it satisfies our needs, and we added this constructor to shared_ptr class:
template
shared_ptr(Y* y, shared_ptr<Z> const & z): px(z.px ? y : 0), pn( y ? z.pn : detail::shared_count() ) // never throws
[...]
Finally our question is:
Is there an easyer way to solve our problem?
If the answer is yes we want to know it and
if the answer is no we want to know if you can enhace shared_ptr to solve this kind of problem.
I think that you have described the various approaches to the problem quite well. The only alternative that comes to mind is to switch from containment to inheritance: class Y {}; class X: public Y, public enable_shared_from_this<X> { public: shared_ptr<Y> ptr_y() { return shared_from_this(); } }; or class X: private Y, public enable_shared_from_this<X> { public: friend class shared_ptr<Y>; shared_ptr<Y> ptr_y() { return shared_from_this(); } }; This of course is not a general solution. I have considered a constructor similar to your proposal... it is unsafe, but powerful. The current design approach is to provide safer, but more restricted versions, like static_pointer_cast. An alternative would be to add template<class Y> shared_ptr(shared_ptr<Y> const & r, T Y::* pm): px(&((*r).*pm)), pn(r.pn); but this is still not a general solution.