Зачем создавать объект с возвращающим членом stati c shared_ptr? - PullRequest
2 голосов
/ 07 мая 2020

Я видел такой узор повсюду, и мне любопытно, в чем польза от такого узора. В чем разница между созданием объекта с помощью stati c и чистого конструктора?

class Foo {
static std::shared_ptr<Foo> create(); // why expose this function?

Foo(folly::observer::Observe<Config> config);
};

1 Ответ

1 голос
/ 07 мая 2020

Одна из причин сделать это - заставить все экземпляры объекта принадлежать shared_ptr (вместо статически построенных). Это особенно полезно при использовании shared_from_this ().

Например, рассмотрим следующую программу:

#include <memory>

class Foo;

void globalFunc(const std::shared_ptr<Foo> &) {
    // do something with the ptr
}

class Foo
    : public std::enable_shared_from_this<Foo>
{
public:
    Foo() {}
    void classMemberFunc()
    {
        globalFunc(shared_from_this());
    }
};

В этой программе объект Foo может получить доступ / передать общий указатель на сам , аналогично тому, как он может получить / передать указатель this. Когда classMemberFun c () вызывается для объекта Foo, globalFun c получает ссылку на shared_ptr, удерживаемую Foo.

Однако в этом дизайне Foo должен принадлежать shared_ptr в первое место.

int main()
{
    // valid use
    auto sptr = std::make_shared<Foo>();
    sptr->classMemberFunc();
}

Если объект Foo не принадлежит shared_ptr, shared_from_this () имеет неопределенное поведение до C ++ 17 и ошибку времени выполнения в C ++ 17.

int main()
{
    // invalid use - undefined behavior or runtime error
    Foo nonPtrFoo;
    nonPtrFoo.classMemberFunc();
}

Мы хотели бы предотвратить это во время компиляции. Мы можем сделать это с помощью метода stati c "create" и частного конструктора.

class Foo
    : public std::enable_shared_from_this<Foo>
{
public:
    static std::shared_ptr<Foo> create() // force shared_ptr use
    {
        return std::shared_ptr<Foo>(new Foo);
    }
    void classMemberFunc()
    {
        globalFunc(shared_from_this());
    }
private:
    Foo() {} // prevent direct construction
};

int main()
{
    // valid use
    auto sptr = Foo::create();
    sptr->classMemberFunc();

    // invalid use - now compile error
    Foo nonPtrFoo;
    nonPtrFoo.classMemberFunc();
}
...