unique_ptr的有效性



当我在c++11中看到std::unique_ptr时,我就很喜欢它,但我很长一段时间都在质疑它的有效性。(有关实时代码的链接,请参阅下面的链接(:

#include <memory>
std::unique_ptr<int> get();
extern std::unique_ptr<int> val;
void foo()
{
    val = get();
}

这给了我16条关于-O3最后叮当声的指示。但更有趣的是,它生成了两个对delete的调用,尽管第二个永远不会被调用。

我试着这样做:

void foo()
{
    auto ptr = get().release();
    val.reset(ptr);
}

突然间,只有11条指令。然后我更深入地攻击了unique_ptr move ctor。最初它被实现为reset(__u.release());。我基本上只是重新排序如下:

auto& ptr =  _M_ptr();
if (ptr)
    _M_deleter()(ptr);
ptr = __u.release();

Aand。。。。手动管理版本中的11条指令。这略有不同,但似乎还可以。

我把实验保存在这里。

有人能指出是我错过了什么吗?还是这实际上是有意为之?

移动分配的操作顺序必须为:

  1. 制作托管源指针的副本,并在源对象中将其置空
  2. 如果目标托管指针不为null,请将其删除
  3. 在目标对象中设置目标托管指针

请注意,这种逻辑很好地导致了自移动分配的无操作。

逻辑必须是这样的原因是源可能由目的地所有。

想象一下:

struct list { std::unique_ptr<list> next; };
std::unique_ptr<list> head;
// ...
if (head) head = std::move(head->next);

如果head->next的托管指针在删除由head管理的旧对象之前没有为null,则这将不会正常工作。

因此,在代码中,移动分配只是:

reset(source.release())

您的最后一个代码片段显然无法在删除前使源为null,因此对于移动分配来说不是一个可行的实现:

auto& ptr =  _M_ptr();
if (ptr)
    _M_deleter()(ptr);
ptr = __u.release();

这就留下了为什么的问题

val = get();

与不同

auto ptr = get().release();
val.reset(ptr);

区别在于从get()返回的隐式unique_ptr<int>。在第一个版本中,它在releasereset之后被销毁。在第二个版本中,它在release之后但在reset之前被销毁。在这两种情况下,它在被销毁时都为null,不需要进行删除。但是编译器一定无法在reset中传播此指针为空的知识。

相关内容

  • 没有找到相关文章

最新更新