Boost logo

Boost :

Subject: Re: [boost] [SmartPtr] alternative to enable_shared_from_this
From: Jared Grubb (jared.grubb_at_[hidden])
Date: 2017-01-05 20:54:18


> El ene. 5, 2017, a las 10:02, Roberto Hinz <robhz786_at_[hidden]> escribió:
>
> On Thu, Jan 5, 2017 at 1:13 PM, Boris Rasin <boris_at_[hidden] <mailto:boris_at_[hidden]>> wrote:
>
>> Here is how I fixed multiple inheritance problem:
>>
>> template <typename T>
>> class virtual_shared_from_this : public virtual
>> std::enable_shared_from_this<void>
>> {
>> public:
>> std::shared_ptr<T> shared_from_this()
>> {
>> return std::shared_ptr<T>(std::enable_shared_from_this<void>::shared_from_this(),
>> static_cast<T*>(this));
>> }
>> };
>>
>> You use virtual_shared_from_this exactly as you would use
>> enable_shared_from_this. It supports multiple inheritance and is very
>> efficient (no use of dynamic_cast).
>
>
>
> This indeed solves the problem of multiple inheritance. But I think I
> didn't expose well enough the other problem, which has to do with cyclic
> references:
>
> Suppose an object A has a shared_ptr to an object B which has a weak_ptr to
> A. Every time this weak_ptr is used, it may not be eligible anymore to
> originate a non null shared_ptr. In this case, if B can nicely handle this
> locally ( checking the result of weak_ptr<A_type>::lock() ), then fine. But
> if it can't, is has to throw an exception. And this can be highly
> undesirable. One way to solve this problem would turn B a member object of
> A, or manage B with a unique_ptr owned by A. This way we ensure that A is
> never destroyed before B. But suppose that for some reason, there is
> something that requires a shared_ptr to B. How do you solve that?

For this exact scenario, you can use the aliasing constructor of shared_ptr (for reference, see constructor #8 on http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr <http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr>):

class A
: public std::enable_shared_from_this<A>
{
     // ...
protected:
        std::shared_ptr<B> make_B_handle() const {
                return std::shared_ptr<B>{ shared_from_this(), b_.get() };
        }
private:
        std::unique_ptr<B> b_;
};

The aliasing constructor says roughly that "I know that the pointer I'm giving you (the B* in this case) is valid if and only if the shared_ptr<A> is valid". You could even have the B directly in the A instead of via a unique_ptr (and then you give &b_ instead of b_.get()).

>
> I have to agree that this is a very specific situation. But when it
> happens, it seems that it can only be solved with shared_handle ( or with
> enable_shared_from_raw which has no doc and I didn't know exists until now
> ).
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost <http://lists.boost.org/mailman/listinfo.cgi/boost>


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk