Boost Shared_Ptr 赋值

6
为什么我不能这样做?
boost::shared_ptr<QueuList> next;

void QueuList::SetNextPtr(QueuList* Next)
{
    boost::mutex mtx;

    boost::mutex::scoped_lock lock(mtx);
    {// scope of lock
        //if (next == NULL)  // is this needed on a shared_ptr??
        next = Next;  // Why can I not assign a raw ptr to a shared_ptr????
    }

我该怎么做呢?

编辑:当下一个变量被正确赋值时调用此方法,但是由于某种原因QueuList对象被销毁时仍会导致错误。我得到了一个调试断言。对象的析构函数没有特别的操作。只有在调用这个函数时才会崩溃:

    QueuList li;
    QueuList lis;

    li.SetNextPtr(&lis);

当主函数结束时,我收到一个调试断言...有什么想法吗?

1
根据您的编辑修改了我的答案。 - Björn Pollex
3个回答

7

这样做是为了防止意外地将指针分配给独立管理生命周期的shared_ptr。您必须明确创建一个shared_ptr,然后才能接管该对象。

next = boost::shared_ptr<QueueList>( Next );

关于你的修改 问题在于,在你的情况下,shared_ptr 接管了一个位于栈上的对象。这时会出现两种情况:

  1. 对象的堆栈帧在 shared_ptr 达到引用计数为 0 之前被清除。在这种情况下,shared_ptr 将尝试在稍后的某个地方删除一个不存在的对象,导致未定义的行为。
  2. shared_ptr 达到引用计数为 0 之前,堆栈帧被清除。在这种情况下,它将尝试删除一个位于栈上的对象。我不确定在这种情况下会发生什么,但我认为这也是未定义的行为。

5
可以使用重置成员函数 - next.reset(Next); - Paul Groke

6

您可以使用Reset()函数,而不是更冗长的next = boost::shared_ptr<QueueList>(Next);

next.Reset(Next);

5

将指针放入shared_ptr中会将指针的所有权转移给shared_ptr,因此shared_ptr负责删除它。这是一个重要的概念操作,因此shared_ptr的设计者不希望它只是作为一个正常赋值的一部分而发生。例如,他们想防止以下代码:

some_shared_ptr = some_other_smart_pointer.get();

这段文字涉及IT技术,讲的是智能指针的问题。其中一段话提到了“double-delete”(双重删除)的情况,也就是两个智能指针都认为自己应该负责清理指针,并且可能会导致指针被重复删除或类似的情况。
而你遇到的调试断言问题正是因为这个原因。调用 SetNextPtr(&lis)&lis 的所有权转移给了 shared_ptr,"所有权" 意味着当最后一个 shared_ptr 副本超出作用域时,它将调用其指向的对象的 delete 方法进行清理。因此,实际上你正在删除一个本地(栈)变量 - lis,这会破坏堆栈并导致崩溃。

如果lis本身是一个指针,将其传递给此函数是否会使其被shared_ptr所拥有,还是我仍然需要删除我的lis指针? - Tony The Lion
你不需要删除 lis 指针 - 你只需要删除从 new 获取的指针,事实上你必须 * 仅 * 对由 new 返回的指针调用 delete。根据当前函数的编写,完全不应将 lis 指针传递给此函数,因为 &lis 不是从 new 获取的指针,并且该函数将隐式地删除其参数。 - Doug
我在谈论指针时是这样的:QueuList* lis = new QueuList(); - Tony The Lion
2
好的,如果你将new QueuList()的结果传递给该函数,那么你就不需要(也不应该)在其他任何地方删除它。 - Doug

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