使用this实例化Boost::shared_ptr

3
考虑以下情况:
typedef boost::shared_ptr<B> BPtr;

class A
{
public:
    A() { b_ptr = BPtr(new B); }
    void a_func() { C::c_func(b_ptr); }
private:
    BPtr b_ptr;
}

class B
{
public:
    B() { b_ptr = BPtr(this); }
    void b_func() { C::c_func(b_ptr); }
private:
    BPtr b_ptr;
}

class C
{
public:
    static void c_func(BPtr b_ptr) { /*...*/ }
}

this实例化shared_ptr是否可以?
两个shared_ptr对象指向同一对象是否可以?(例如A::b_ptr和B::b_ptr)
如果这两个中的一个超出范围 - B的实例会被删除吗?
我猜我做错了一些根本性的事情。
我还考虑过将b_ptr注入B的构造函数,但那也似乎非常错误。
更新:
澄清一下 - A和B都需要使用C::c_func。反过来,在一些处理之后,C需要在B中调用回调函数,我没有在上面指定。 实际上有两种有趣的情况:
1. 如果有一个要求C不具有状态性的要求 - 那么它需要从A和B中都接收BPtr,就像上面的代码一样。 2. 如果C是有状态的,并且A和B实例化单独的C实例,则在C的ctor中给出BPtr。
2个回答

10
能否使用this来实例化一个shared_ptr?
不行,至少有以下几个原因: 1. 如果在堆栈或静态上创建A或B对象,则会得到一个“拥有”在堆栈上创建的对象的shared_ptr;当对象被销毁时,shared_ptr析构函数将被调用,在对象上调用delete,会发生一些非常糟糕的事情。此外,即使对象是动态创建的,也无法确定类的所有者可能会对其进行什么操作:他可能会将其分配给其他类型的智能指针(如auto_ptr),其语义完全不同。 2. 你将得到一个循环引用。例如,b_ptr拥有它所属的B对象。必须手动重置才能销毁B对象。 可以通过使用enable_shared_from_this从this获取shared_ptr,但是存在许多注意事项:即不能在构造函数中调用enable_shared_from_this。即使这样,您也不应在对象本身内部存储指向对象的shared_ptr;这毫无意义。
我猜我做错了什么根本性的事情。
是的,但由于您没有说出您要做什么,因此很难说您应该做什么。您只告诉我们您尝试以何种方式执行此操作,而没有说出您首先要执行什么操作。

我给你打了分,但我有点不同意。说不能使用this实例化shared_ptr意味着enable_shared_from_this不应该存在,这是不正确的。这里的问题在于,将shared_ptr作为成员变量指向this是不可取的。 - Omnifarious
@Omnifarious:我认为我说的是真的:你永远不应该(至少显式地)使用this实例化一个新的shared_ptr对象;这样做要么非常错误,要么就是完全不正确的。你可以使用安全的库提供的enable_shared_from_this设施来_隐式_地这样做。虽然我几乎可以确定OP是在问显式形式。 - James McNellis
请注意,enable_shared_from_this 要求在使用它之前必须通过“正常”方式创建一个 shared_ptr - bdonlan
@Jonathan:C是否真的需要“拥有”B对象?它一定要使用shared_ptr<B>吗?或者可以改为使用B&吗? - James McNellis
@Jonathan:很高兴听到这个消息。shared_ptr只应用于表达共享所有权,因此如果某些东西不需要对象的所有权,则引用或原始指针可能更合适(尽管这通常取决于具体情况)。如有任何进一步问题,请随时提问! - James McNellis
显示剩余2条评论

0
我建议您重新设计并使用std::enable_shared_from_this,例如:
class B
{
   B();
public:
   std::shared_ptr<B> create() { return std::make_shared<B>(); } // Make sure B is allocated as shared_ptr inorder to ensure that shared_from_this() works.
};

然而,如果你遇到的是API问题,那么你可以执行以下操作(尽管我不建议这样做)。
void b_func() { C::c_func(BPtr(this, [](B*){})); } // Empty deleter. Nothing happens when shared_ptr goes out of scope. Note that c_func cannot take ownership of the pointer.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接