两个阶段构造,在派生类的对象创建期间使用shared_from_this()

时间:2015-02-25 06:47:10

标签: c++ c++11 shared-ptr

我有一个基类继承自enable_shared_from_this

的设置
class Object : public enable_shared_from_this<Object>
{ ... };

我从enable_shared_from_this继承,因为我需要经常调用shared_from_this()。在Object的某些派生中,我需要在构造函数中调用with的from_from_this(),这不能完成:

class Thing : public Object
{
public:
    Thing() : Object(...) 
    { doSomething(shared_from_this()); /* error */ }
};

因此,解决方案是两阶段构建。

class Thing : public Object
{
public:
    Thing() : Object(...) {  }
    void Init() { /* safe to call shared_from_this here */ }
};

创建Thing对象的有效方法是:

shared_ptr<Thing> thing = make_shared<Thing>();
thing->Init();

这不是很好并且容易出错,但至少它有效。但是,现在还存在进一步继承的问题:

class Bling : public Thing
{
public:
    Bling() : Thing(...) { ... }
    void Init() { /* safe to call shared_from_this here */ }
};

// How do we create a Bling object?
shared_ptr<Bling> bling = make_shared<Bling>();
static_cast<Thing*>(bling.get())->Init(); // horrible
bling->Init();

// Maybe Bling::Init should look like:
// Bling::Init() { Thing::Init(); /* + other stuff */ }
// then we could do:
shared_ptr<Bling> bling = make_shared<Bling>();
bling->Init(); // etc

有更安全或更清洁的方法吗?例如,API明智的是它更容易出错,使Object,Thing和Bling的构造函数变得私有,并使用创建shared_ptr的静态Init()函数:

static shared_ptr<Bling> Bling::Init() {
    auto bling = make_shared<Bling>();
    Bling::init(bling);
    return bling;
}

static void Bling::init(shared_ptr<Bling> bling) {
    /* chain parent class init */
    Thing::init(bling); // sig: Thing::init(shared_ptr<Thing>);

    /* do init stuff */
}

// calls Object(), Thing(), Bling(), 
// Object::init(), Thing::init(), Bling::init()
auto bling = Bling::Init();

基本上我正在寻找模式来实现对象创建,我可以在创建过程中使用shared_ptr来创建对象。我需要允许基本继承。我想建议考虑最终用户易用性和开发人员可维护性的方法。

1 个答案:

答案 0 :(得分:1)

您可能不应该依赖于对象的用户最初始终将其保存在共享指针中这一事实。设计类,以便在堆栈和堆上允许对象。

如何解决这个问题取决于你对shared_from_this()返回的指针的处理方式。

我想到的一件事是对象在某处注册 - 即在对象之外。在我看来,最好在从Object派生的数据类之外做到这一点。如果您有一个类Registry的注册表对象,请将其转换为工厂(由David Schwartz建议):

class Registry;

class Object
{
protected:
    Object() = default;
    friend Registry;
public:
    // ...
};

class Thing : public Object
{
protected:
    Thing() = default;
    friend Registry;
public:
    // ...
};

class Registry
{
    vector<shared_ptr<Object>> store;
public:
    shared_ptr<Thing> CreateThing()
    {
        shared_ptr<Thing> newThing = make_shared<Thing>();
        newThing->init(); // If you like.
        store.push_back(newThing);
        return newThing;
    }
    shared_ptr<Bling> CreateBling();
    // ...
};
  • 根本不需要enable_shared_from_this
  • 更容易理解。
  • 责任明确。
  • 轻松更改,以便允许未注册的ObjectThing个对象。 (抓取受保护的构造函数和friend声明。)

可能已经很清楚,但只是为了确定:我不赞成enable_shared_from_this。它假定在​​shared_ptr时调用对象由shared_from_this()进行管理。如果不是这种情况,则&#34;行为未定义&#34;。如果至少它会是例外,或者nullptr将被退回......

当初始shared_ptr的创建和shared_from_this()的调用在代码中彼此接近时(无论这意味着什么),这样的假设是可以的。有没有人有这个用例?我不喜欢。