我明白为什么 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 指针。这只是我稍后想要菊花链的副作用。
一个肮脏的修复可能是我只做了一堆私有(private)的 setX_ 方法来执行实际的分配和其他任务,但不返回任何东西。构造函数调用那些。然后我有公共(public) setX 方法,只需调用私有(private)方法,然后返回 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_ptr 的方法,所以我可以转换为 weak 或在需要时检查 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();
}
};
最佳答案
我想添加到@JoachimPileborg 的正确评论中。我不认为你的问题真的与如何使用enable_shared_from_this
的技术细节有关,而是何时使用(智能)指针。
考虑以下代码,展示了两种使用链式调用的方法:
struct ptr_foo
{
ptr_foo *set_x(int x) { return this; }
ptr_foo *set_y(int y) { return this; }
};
struct ref_foo
{
ref_foo &set_x(int x) { return *this; }
ref_foo &set_y(int y) { return *this; }
};
int main()
{
ptr_foo pf;
pf.set_x(0)->set_y(1);
ref_foo rf;
rf.set_x(0).set_y(1);
return 0;
}
第一个类 ptr_foo
使用原始指针,第二个类 ref_foo
使用引用。
首先,第二次调用,
rf.set_x(0).set_y(1);
在我看来比第一个更一致,
pf.set_x(0)->set_y(1);
对于基于堆栈的对象的常见情况。
此外,即使您更喜欢第一个,我认为没有任何理由返回智能指针,因为
没有分配发生
该协议(protocol)并不是为了通过调用
set_?
获取指向ptr_foo
的可存储指针;如果有人这样做,那就是对协议(protocol)的滥用,因为它只适用于链式调用。
关于第 2 点,无论如何您都无法完全关闭协议(protocol)滥用行为。例如,考虑
ptr_foo pf;
ptr_foo *ppf = &pf;
无论您如何设计 ptr_foo
,用户现在都持有指向该类型对象的指针,该对象不是动态分配的,并且可能会被错误地删除。
关于c++ - 链式调用构造函数中 shared_from_this 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35098984/