Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't aliasing constructor of std::shared_ptr initialize std::enabled_shared_from_this?

Consider the following code:

struct Foo : std::enable_shared_from_this<Foo>
{

};

struct Bar
{
    Foo foo;
};

int main()
{
    std::shared_ptr<Bar> bar_p(new Bar);

    //make shared_ptr to member with aliasing constructor
    std::shared_ptr<Foo> foo_p(bar_p, &bar_p->foo);
    assert(bar_p->foo.shared_from_this()); //fail! throws bad_weak_ptr
}

Unfortunately, it doesn't work as expected (at least in GCC 4.8.2). I looked into code and it seems that aliasing constructor simply doesn't call __enable_shared_from_this_helper() which is necessary for proper work of shared_from_this().

Does anybody have any idea why it was designed in such a way? Is there something wrong with returning shared_ptr to member from shared_from_this?

like image 211
peper0 Avatar asked Jun 12 '15 08:06

peper0


1 Answers

[util.smartptr.shared.const]

template<class Y> shared_ptr(const shared_ptr<Y>& r, T* p) noexcept;

Effects: Constructs a shared_ptr instance that stores p and shares ownership with r.

foo_p takes no ownership of bar_p->foo when you call the aliasing constructor, which in this case is a very good thing because otherwise it would try to delete it on destruction.

[util.smartptr.enab]

shared_ptr<T> shared_from_this();

shared_ptr<T const> shared_from_this() const;

Requires: [...]There shall be at least one shared_ptr instance p that owns &t.

As bar_p->foo isn't owned by at least one shared_ptr you end up with undefined behavior, gcc throws bad_weak_ptr but it isn't obliged to do anything helpful.

like image 123
user657267 Avatar answered Oct 26 '22 23:10

user657267