std::unique_ptr 构造函数行为

std::unique_ptr constructor behaviour

首先,我知道我们应该使用 std::make_unique() 而不是调用 std::unique_ptr 构造函数,我知道为什么。

但我正在查看 std::unique_ptr 的文档来打发时间并加深对它的了解,我发现 following examples 关于构造函数的用法:

// unique_ptr constructor example
#include <iostream>
#include <memory>

int main () {
  std::default_delete<int> d;
  std::unique_ptr<int> u1;
  std::unique_ptr<int> u2 (nullptr);
  std::unique_ptr<int> u3 (new int);
  std::unique_ptr<int> u4 (new int, d);
  std::unique_ptr<int> u5 (new int, std::default_delete<int>());
  std::unique_ptr<int> u6 (std::move(u5));
  std::unique_ptr<int> u7 (std::move(u6));
  std::unique_ptr<int> u8 (std::auto_ptr<int>(new int));

  std::cout << "u1: " << (u1?"not null":"null") << '\n';
  std::cout << "u2: " << (u2?"not null":"null") << '\n';
  std::cout << "u3: " << (u3?"not null":"null") << '\n';
  std::cout << "u4: " << (u4?"not null":"null") << '\n';
  std::cout << "u5: " << (u5?"not null":"null") << '\n';
  std::cout << "u6: " << (u6?"not null":"null") << '\n';
  std::cout << "u7: " << (u7?"not null":"null") << '\n';
  std::cout << "u8: " << (u8?"not null":"null") << '\n';

  return 0;
}

它生成(我通过执行代码验证了它)以下结果:

u1: null
u2: null
u3: not null
u4: not null
u5: null
u6: null
u7: not null
u8: not null

我很难理解的是:

也许这些问题很基础,但我完全没有抓住要点。

如果有哪位大神能解答一下这些问题,不胜感激

std::move 被命名为 move 是有原因的。当你从一个 std::unique_ptr 移动到另一个时,你移动的那个变成 nullptr。不可能有任何其他方式,毕竟它是一个 unique ptr,两个 unique_ptr 实例共享相同的数据会违反这一点。 (而且都超出范围会调用删除器两次,然后一切都松散了。)

Why is u4 valid while u5 is not (nullptr) ?

因为u5是在u6的初始化中移出的,而u4还没有移出。 move 构造函数保证将 moved from 指针设置为 null。它不能指向与 u6 相同的对象,因为那样会违反唯一性约束。

Why is u7 valid but not u6 ?

同理。

移动一个唯一拥有的对象意味着新的所有者拥有它而以前的所有者一无所有。
就像物理对象在现实世界中的工作方式一样。

拥有者转为空指针,说明一无所有。

最初由 u5 拥有的对象已先移至 u6,然后移至 u7