在移动“unique_ptr”时,我们真的需要确保放弃所有权吗?

Gil*_*ils 6 c++ move move-semantics c++11

我正在阅读 Nicolai M. Josuttis 的《C++ Move Semantics - The Complete Guide》一书(恕我直言,这本书相当不错),我不确定我是否同意其中一个示例中的评论。

引用(来自 6.1.2 - 移出对象的保证状态):

类似的代码可用于释放唯一指针使用的对象的内存:

draw(std::move(up));  // the unique pointer might or might not give up ownership
up.reset();           // ensure we give up ownership and release any resource
Run Code Online (Sandbox Code Playgroud)

让我们假设up变量确实是unique_ptr,并且draw函数接收unique_ptr值(否则,将指针移动到“passed-by-ref”函数有什么意义)。

reset我知道调用“移出”对象是合法的。但我不明白的是为什么它是“必需的”,以便“确保我们放弃所有权并释放任何资源”以及“唯一指针可能会或可能不会”是如何可能的放弃所有权”怎么可能?

毕竟,unique_ptrs 无法复制,而且整个想法是它们仅保证一种所有权。

因此,据我所知,如果我的两个假设是正确的,则无需调用该reset函数来确保所有权被放弃。

我错过了什么吗?

Jan*_*tke 5

首先,如果参数被值接受,那么我们就可以保证它实际上是被移动的,而不仅仅是可能,并且放弃了资源的所有权(除非移动构造函数不执行任何操作,但这会是无意义的)。.reset()由于两个可能的原因,我们可能不得不另外调用:

\n

如果.reset()参数并不总是

\n

考虑以下签名:

\n
void draw(std::unique_ptr<T> &&uptr);\n
Run Code Online (Sandbox Code Playgroud)\n

这样的签名通常优于通过CppCoreGuidelines F.18 按值接受移出参数:对于 \xe2\x80\x9cwill-move-from\xe2\x80\x9d 参数,通过 X&& 和 std::move 参数传递,尽管像这样的类型有例外std::unique_ptr

\n

在这种情况下,除非我们查看其实现,否则我们不知道是否会draw从“确定”移动:uptr

\n
void draw(std::unique_ptr<T> &&uptr) {\n    // If \'condition\' is false, then \'uptr\' won\'t be moved from, and the\n    // caller may have to .reset() to free up resources immediately.\n    if (condition) {\n        process_further(std::move(uptr));\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

您可能需要.reset()交换移动分配

\n

此外,一些人倾向于按如下方式实现移动赋值运算符:

\n
T& operator=(T&& other) noexcept {\n    this->swap(other);\n    return *this;\n}\n\nvoid draw(std::unique_ptr<T> &&uptr) {\n    // This effectively swaps \'something\' with \'uptr\', which means that\n    // the caller has to .reset() to free the resources in \'something\',\n    // unless they can rely on the destructor of \'uptr\' to do that.\n    something = std::move(uptr);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这会强制调用者在希望立即释放这些资源时使用.reset(),而不是在参数超出范围时使用。

\n

没有标准库类型实现这样的移动分配,总的来说这不是一个好主意,但它是有效的,并且可能会迫使我们进行调用。

\n