7

我试图了解如何实现unique_ptr 的 C++03 仿真。unique_ptr 很像 std::auto_ptr 但更安全。在 auto_ptr 隐式转移所有权(即,静默)的情况下,它会吐出编译器错误。例如,一个简单的分配。功能move是模拟 unique_ptr 安全性的关键。

问题:

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

    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>参数。这是为什么?detail_unique_ptr::rv<T>unique_ptr 已经定义了一个作为参数的(非显式)构造函数。为什么不自动捡起那个?

4

1 回答 1

3

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

当从同一个类的对象复制一个类的初始化时,没有这样的两步初始化。源对象只是传递给 的非显式构造函数unique_ptr,它会将其转换为rv使用 rv-take 构造函数,并通过这种方式成功构造返回值目标对象。

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

于 2011-12-09T21:53:52.677 回答