lundi 27 juin 2016

Getting a unique_ptr for a class that inherits enable_shared_from_this

Usually I prefer returning unique_ptr from Factories. Recently I came to the problem of returning a unique_ptr for a class that inherits enable_shared_from_this. Users of this class may accidentally cause a call to shared_from_this(), though it is not owned by any shared_ptr, which results with a std::bad_weak_ptr exception (or undefined behavior until C++17, which is usually implemented as an exception).

A simple version of the code:

class Foo: public enable_shared_from_this<Foo> {
    string name;
    Foo(const string& _name) : name(_name) {}
public:
    static unique_ptr<Foo> create(const string& name) {
        return std::unique_ptr<Foo>(new Foo(name));
    }
    shared_ptr<Foo> get_shared() {return shared_from_this();}
    void doIt()const {cout << "Foo::doIt() <" << name << '>' << endl;}
    virtual ~Foo() {cout << "~Foo() <" << name << '>' << endl;}
};

int main() {
    // ok behavior
    auto pb1 = Foo::create("pb1");
    pb1->doIt();
    shared_ptr<Foo> pb2 = shared_ptr<Foo>(std::move(pb1));
    shared_ptr<Foo> pb3 = pb2->get_shared();
    pb3->doIt();

    // bad behavior
    auto pb4 = Foo::create("pb4");
    pb4->doIt();
    shared_ptr<Foo> pb5 = pb4->get_shared(); // exception
    pb5->doIt();    
}

A possible solution is to change the factory method to return shared_ptr but this is not what I'm looking for, as in many cases there is actually no need for sharing and this will make things less efficient.

The question is how to achieve all of the following:

  1. allow the factory to return unique_ptr
  2. allow unique_ptr of this class to become shared
  3. allow shared_ptr of this class to get shared copies (via shared_from_this())
  4. avoid failure when unique_ptr of this class tries to get shared from this (calling get_shared in above example)

Items 1 to 3 are fulfilled with the code above, the problem is with item 4.

Aucun commentaire:

Enregistrer un commentaire