【发布时间】:2023-03-05 14:29:01
【问题描述】:
我明白为什么 shared_from_this 在构造函数中不起作用。我在这里clearly 上找到了许多帖子来解释原因。我还看到了workaround。我的问题与此有关,但我正在寻找一种优雅的解决方法。
我很喜欢这样的设计
class Foo : public enable_shared_from_this<Foo> {
public:
typedef shared_ptr<Foo> Ptr;
Ptr setA(int) {/* .... */ return this->shared_from_this(); }
Ptr setB(int) {/* .... */ return this->shared_from_this(); }
Ptr setC(int) {/* .... */ return this->shared_from_this(); }
};
所以我可以像这样菊花链,我觉得它非常易读
Foo::Ptr foo = make_shared<Foo>();
foo->setA(3)->setB(4)->setC(5);
但是,我的 setX 方法不仅仅是将值分配给属性,它们可能会做一些更复杂的事情(例如设置其他属性等)。所以我想在我的构造函数中使用它们。即
Foo::Foo(int a, int b, int c) {
setA(a);
setB(b);
setC(c);
}
这当然会崩溃。但是在我的情况下,我的构造函数中实际上并不需要共享的 this 指针。这只是我以后想要菊花链的副作用。
一个肮脏的修复可能是我只是做了一堆私有的 setX_ 方法来执行实际的分配和其他任务,但不返回任何东西。构造函数调用那些。然后我有公共的 setX 方法,只需调用私有的方法,然后返回 this->shared_from_this()。这很安全,但有点像 PITA。是否可以检查指向 this 的共享指针是否已经存在而不会崩溃?即
class Foo : public enable_shared_from_this<Foo> {
public:
typedef shared_ptr<Foo> Ptr;
Ptr setA(int) { /*.....*/ return getThis(); }
protected:
Ptr getThis() {
return safe_to_get_this ? this->shared_from_this : Ptr();
}
};
更新
我应该在我原来的帖子中说明这一点,很抱歉没有这样做。我使用智能指针的原因不是我可以进行菊花链。如果情况允许,我通常会使用参考。
但在这种情况下,Foo(和其他类)属于类似图的结构,它们相互依赖、多个父子兄弟关系等。所以我使用了共享指针和弱指针之间的混合。但是我需要返回 shared_ptrs 的方法,所以如果需要,我可以强制转换为弱或检查 null(它们是使用工厂方法创建的,并且也有 find/get 方法需要检查 null)。基本上它是一个物理系统,具有不同类型的粒子和粒子之间的约束。很多年前我最初用自己的智能指针实现写了这个,现在我将它升级到 c++11。我可以让 setX 方法返回引用,并让单个 getThis() 方法返回共享指针(这是我之前所做的),但是我担心它与一些返回智能指针的方法有点不一致,而其他返回的智能指针参考。
Foo::Ptr foo = World::create();
foo->setA().setB().setC();
foo = World::find(...);
if(foo) foo->setA().setB();
我只是更喜欢始终返回指针的一致性,而不是有时指针有时引用。除非对此有严格的指导方针,可以简明扼要地总结。
更新2
这是我目前使用的(不是很优雅的)解决方法。我只是想知道是否有一种方法可以在不手动跟踪 _isInited 的情况下执行此操作;
class Foo : public enable_shared_from_this<Foo> {
public:
typedef shared_ptr<Foo> Ptr;
Foo() {
_isInited = false;
setA();
setB();
setC();
_isInited = true;
}
Ptr setA(int) {/* .... */ return getThis(); }
Ptr setB(int) {/* .... */ return getThis(); }
Ptr setC(int) {/* .... */ return getThis(); }
protected:
bool _isInited;
Ptr() {
return _isInited ? this->shared_from_this() : Ptr();
}
};
【问题讨论】:
-
如果你只想将成员函数调用链接在一起,为什么要使用指针开头呢?只需返回对类本身的引用,您不必担心
shared_from_this等。我建议您从 资源所有权 的角度来看智能指针,而不仅仅是简单的指针会被自动删除。
标签: c++ c++11 constructor smart-pointers