【问题标题】:Appropriate use for boost::shared_ptr?boost::shared_ptr 的适当用途?
【发布时间】:2012-03-26 12:02:12
【问题描述】:

这里有一个关于boost::shared_ptr的问题:

我有 3 个课程。

A 是某种 Main 类,负责管理所有内容。

B 是一个类,它只具有执行某些工作的功能。

Dispatcher 只是一个封装了一个单独线程的类,它从该线程中Bdone 的 Instaces 获取工作。

所以它有点像这样工作:A 有一个Dispatcher 的实例。现在偶尔A 会生成B 的实例并将其传递给调度程序。

重要的是,B 完成后需要调用A::callback()。这就是为什么B 在其构造函数中获得对 A 的引用(参见下面的代码)

A.hpp

class A : public boost::enable_shared_from_this<A>
{
public:
    A();
    void sendB();
    void callback();
private:
    Dispatcher m_Dispatcher;
};

B.hpp

class B
{
public:
    B(boost::shared_ptr<A> ptr);
    boost::shared_ptr<A> m_PointerToA;
 /* Some other functions */
};

Dispatcher.hpp

class Dispatcher
{
public:
     void run();
     void dispatch(boost::shared_ptr<B> b);
private:
     void doWork();
     boost::thread m_Thread;  
};

A.cpp

A::A()
{
    m_Dispatcher.run();
}
void A::sendB()
{
    boost::shared_ptr ptr_B;
    ptr_B.reset(new B(this->shared_from_this);
    m_Dispatcher.dispatch(ptr_B);
}

B.cpp

B::B(boost::shared_ptr<A> ptr) :
    : m_PointerToA(ptr)
{
}

main_example.cpp

int main()
{
     A instanceA;
     while(true)
     {
          instanceA.sendB();
          /* Do some other stuff */
     }
     return 0;
}

所以我的问题是:

为此目的使用 boost::shared_ptr 是否合理?

我不确定shared_ptr 是否适合去这里。我的问题是,当我从B 调用构造函数并将this 指针传递给它时,我不知道究竟会发生什么。现在根据shared_ptr,我假设m_PointerToA 拥有A 的所有权。但这意味着当Dispatcher 中的工作完成并且我的B 实例被删除时,它也会删除对m_PointerToA 的引用,这实际上意味着它会杀死对象本身,尽管事实上存在一个实际的主循环中A 的实例。

更新:

添加了一些代码并更新了问题本身以使其更加清晰。

【问题讨论】:

  • 您不想跨线程边界使用shared_ptr。这是std::auto_ptr 的语义真正闪耀的地方;一旦将指针传递给另一个线程,就无法在原始线程中访问它。
  • boost::shared_ptr 实际上是线程安全的,因为您可以依赖引用计数处于安全状态。
  • @JamesKanze 但我传递的指针实际上是一个this 指针。所以实际上我并没有特别对“指针”做任何事情。但当然,this 的实例中的一些代码仍在主线程中运行。我实际上只是想使用shared_ptr,所以我不会因为丢失引用而遇到任何麻烦。使用原始指针我也没有问题...
  • 我有几个问题。您正在 initClassB 中更新您的 B 实例,但它是如何引用的?如果你将它存储在 A 中,你是怎么做到的?您将它传递给您所说的线程,那么仅从该线程引用吗?问题实际上是关于你希望 A 怎么死。你想让它和另一个线程一起下降吗?就目前而言,B 是 A 的唯一所有者,它将与 B 一起死亡。在这种情况下,我还建议使用 auto_ptr,它可以清楚地说明谁拥有 A 实例。
  • @Dennis Gonna 更新问题,以便更清楚(我第一次写它时省略了一些代码=

标签: c++ pointers boost shared-ptr


【解决方案1】:

这个设计没有什么特别的问题。但是我更愿意使用boost::function&lt;&gt;boost::bind。它为回调提供了更好的灵活性,并且不会将 B 与 A 紧密联系在一起。当然,您仍然必须对通常的线程警告有所不同。

【讨论】:

  • +1。好建议。此外,如果您可以完全控制实例的生命周期,您可以简单地将 reference 存储到您的A。如果你不需要B 当然可以分配。
  • 是的,我也想过让它更通用一点,但在我第一次尝试时,我只是想让它工作。所以实际上使用 boost::shared_ptr 没有问题?
【解决方案2】:

是的,只复制/分配shared_ptr 是可以的,它只会增加引用计数。

在您的示例中,shared_from_this() 将从 weak_ptr 中创建一个(此处:临时)shared_ptr,该 this 持有(参考计数 1),因此当您分配/复制构造 m_PointerToA ,在ctor返回之前引用计数将暂时增加到2并且临时对象将被销毁,引用计数再次减少到1(shared_ptr“知道”你的B对象中的一个实例)。

所以,是的,如果 B 被删除,在这种情况下它将破坏 A(因为引用计数下降到 0)。

您的关心

这意味着如果我的 B 实例被删除,它也会删除 m_PointerToA ,这也会杀死我的 A 实例。当然,我原来的 A 实例在别处。

仅表明如果您计划/需要/打算保留指向 A 实例的指针以供进一步使用,您也应该使用 shared_ptr 而不是原始指针。如果您可以控制A 的界面,最简单的方法是named constructor,如下所示:

class A : public boost::enable_shared_from_this<A> {
    public:
        static boost::shared_ptr<A> create();

        void initClassB();
        // ....
    private:
        A();
        A( const A & other );
        A& operator=( const A & rhs );

};

boost::shared_ptr<A> A::create() {
    return boost::shared_ptr<A>( new A() );
}

那么,即使您的B 实例被删除,A 的实例仍然会存在,因为shared_ptr 的引用计数仍然(至少)为 1。

【讨论】:

  • 好的,我明白为什么您的解决方案会真正确保不会删除 A,因为引用计数至少为 1。但是我想知道:某人(例如 main 函数或另一个类) 需要调用A::create() 方法-因此,如果不使用您的解决方案,这个主函数只会创建一个普通的AI 实例,而B 被删除时可能会丢失它?因此,尽管存在该对象的实际实例,但 A 也会被删除?
  • 不确定您所说的“尽管存在该对象的实际实例”是什么意思。如果引用下降到 0,shared_ptr 将销毁实例。如果B 中只有一个shared_ptrA,是的,销毁 B 将销毁 A 的该实例。如果您通过原始指针在某处引用 A,则无法阻止这种情况。但这就是为什么您应该始终如一地使用智能指针(不要使用指向由智能指针管理的对象的原始指针)。
  • 在上面的例子中,主函数将无法创建A 的“正常”实例(原始指针),因为没有可用/可访问的构造函数(您的编译器将报告错误如果你试试)。构造A 实例的唯一方法是调用A::create()
  • 我在问题中添加了main_example.cpp 以使其更清楚。我只是说,在某处我得到了对象 A 的实际实例 - 现在这意味着我不会像你提到的那样使用 create() 方法 - 导致当 B 被删除时我的 Ref Count 可能会降至 0?
  • 或者让我们换一种方式问我的问题:如果我从boost::enable_shared_from_this&lt;A&gt; 派生出我的class A 并没有隐含地使引用计数为1?
猜你喜欢
  • 2011-08-06
  • 2020-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-04
  • 2021-06-29
  • 2011-04-19
相关资源
最近更新 更多