9

I'm just toying around with the smart pointers in the upcoming new c++ standard. However I fail to grasp the usage of the shared_from_this function. Here is what I have:

#include <iostream>
#include <memory>

class CVerboseBornAndDie2 : public std::enable_shared_from_this<CVerboseBornAndDie2>
{
public:
    std::string m_Name;
    CVerboseBornAndDie2(std::string name) : m_Name(name)
    {
        std::cout << m_Name << " (" <<  this << ") is born!" << std::endl;
    }
    virtual ~CVerboseBornAndDie2()
    {
        std::cout << m_Name << " (" <<  this << ") is dying!" << std::endl;
    }
};

int main(){
    CVerboseBornAndDie2* vbad = new CVerboseBornAndDie2("foo");
    std::shared_ptr<CVerboseBornAndDie2> p = vbad->shared_from_this();
}

and it throws a std::bad_weak_ptr exception in the line

std::shared_ptr<CVerboseBornAndDie2> p = vbad->shared_from_this();

if I instead do

std::shared_ptr<CVerboseBornAndDie2> p(vbad);

it works and I can afterwards do

std::shared_ptr<CVerboseBornAndDie2> p2 = p.get()->shared_from_this();

so must the object belong to one shared_ptr before I can use shared_from_this? But how can I know this beforehand?

fschmitt
  • 3,478
  • 2
  • 22
  • 24

2 Answers2

22

It is a precondition of using shared_from_this that there must exist at least one shared_ptr which owns the object in question. This means that you can only use shared_from_this to retrieve a shared_ptr that owns an object to which you have a reference or pointer, you cannot use it to find out if such an object is owned by a shared_ptr.

You need to rework your design so that either you are guaranteed that any such object is being managed by a shared_ptr or that you don't ever need to know or finally (and least desirably) you create some other way of managing this knowledge.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • Couldn't you just put a try-block around a call to shared_from_this if you wanted to find out if the object is held by a shared_ptr? I don't know how it is specified in the (upcoming) standard, but it doesn't appear to be undefined behavior -- it is throwing an exception. – Brent Bradburn Feb 19 '11 at 05:45
  • 2
    @nobar: This would be inferently unsafe. You would be relying on undocumented implementation detail. `shared_from_this` is not a method for testing whether an object is owned by a shared pointer; it is a method for retrieving a shared pointer from an object that you _know_ is owned by a shared pointer. – CB Bailey Feb 19 '11 at 08:59
  • I think you are right. The C++0x draft says "There shall be at least one shared_ptr instance p that owns &t.", but it doesn't say what happens otherwise. It shows an implementation in terms of weak_ptr (which would imply that an exception will be thrown on error), but that is only a "suggestion". I wonder if the error-handling will eventually be better specified. – Brent Bradburn Feb 20 '11 at 01:32
16

To extend Charles answer, when you use enable_shared_from_this you usually want something like below in order to guarantee that there exists a shared_ptr.

class my_class : public std::enable_shared_from_this<my_class>
{
public:
    static std::shared_ptr<my_class> create() // can only be created as shared_ptr
    {
         return std::shared_ptr<my_class>(new my_class());
    }
private
    my_class(){} // don't allow non shared_ptr instances.
};
ronag
  • 49,529
  • 25
  • 126
  • 221
  • 1
    `create()` should be `static`, doesn't it? – abyss.7 Aug 25 '13 at 16:51
  • 1
    And to have sharing by default, you could use something along the lines of: `try { return shared_from_this(); } catch (const bad_weak_ptr&) { return make_shared(); }` – Jon Purdy Aug 25 '13 at 19:05