unique_ptr c++ 03仿真中的move函数

The move function in unique_ptr C++03 emulation

本文关键字:move 函数 仿真 ptr c++ unique      更新时间:2023-10-16

我试图理解c++ 03仿真unique_ptr是如何实现的。Unique_ptr很像std::auto_ptr,但更安全。当auto_ptr隐式地(即静默地)转移所有权时,它会抛出编译器错误。例如,一个简单的赋值。move函数是仿真unique_ptr安全的关键。

问题:

  1. 为什么有三个移动函数?
  2. 第三个move函数接受引用并将其转换为右值,实现(简化)如下。

    T move(T &t) { 
      return T(detail_unique_ptr::rv<T>(t)); 
    }
    

在上面的代码中,显式转换为T似乎是不必要的。事实上,Visual Studio 2010在没有显式转换为t的情况下是非常完美的。

T move(T &t) {
  return detail_unique_ptr::rv<T>(t);
}
然而,

g++、clang、Comeau都不喜欢第二个版本。这些编译器抱怨没有unique_ptr<T>的构造函数将detail_unique_ptr::rv<T>作为参数。为什么呢?unique_ptr已经定义了一个(非显式的)构造函数,它将detail_unique_ptr::rv<T>作为参数。为什么这个不是自动拾取的?

原因是,如果不进行用户定义的转换(将右值传递给unique_ptr的接受rv的构造函数,就不能用另一个unique_ptr 初始化一个unique_ptr。然而,当没有显式调用unique_ptr的ctor(如unique_ptr(...))时,您执行复制初始化,在您的情况下,它首先成功地构造了一个右值临时unique_ptr,但随后无法将该临时复制到返回值目标对象中,因为在该复制中,不允许用户定义的转换(这也被称为原则规则"初始化中没有两个用户定义的转换")。Msvc允许副本使用接受非const unique_ptr引用的函数,这是非标准的。

从同一类的对象复制类初始化时,不需要这样的两步初始化。源对象只是被传递给unique_ptr的非显式构造函数,后者将使用rv-taking构造函数将源对象转换为rv,并通过这种方式成功地构造返回值目标对象。

出于同样的原因,没有从unique_ptr<Derived>unique_ptr<Base>的隐式转换。在第一步中,将成功创建unique_ptr<Base>,但是当将该临时对象复制到unique_ptr<Base>目标对象时,不能使用任何用户定义的转换的限制阻止了成功。