C++ std:.auto_ptr 或 std::unique_ptr (支持多个编译器,甚至是旧的 C++03 编译器)?

C++ std:.auto_ptr or std::unique_ptr (to support multiple compilers, even old C++03 compilers)?

我正在尝试更新一些 C++ 代码,我想转向更现代的代码 (c++11),但我仍然需要使用一些较旧的编译器 (c++03) 来编译代码兼容),因为受支持的平台限制。

我知道在 C++11 编译器中 std::auto_ptr 已被弃用,但由于较旧的编译器支持,我不能只将它们替换为 std::unique_ptr。

是否有处理此问题的良好做法"old compiler support, but start to move to C++11"?

在这种情况下,您可以使用 boost::unique_ptr 而不是 auto_ptr 来开始现代化您的代码,不推荐这样做。

总的来说,C++11 库的很大一部分直接取自 boost,因此它是一个很好的起点。

如您所述,std::auto_ptr<> 在 C++11 中已被弃用 (Reference).

迁移到 c++11 std::unique_ptr<> 是正确的方法,正如 Herb Sutter 在 GotW89:

  1. What’s the deal with auto_ptr?
    auto_ptr is most charitably characterized as a valiant attempt to create a unique_ptr before C++ had move semantics. auto_ptr is now deprecated, and should not be used in new code.
    If you have auto_ptr in an existing code base, when you get a chance try doing a global search-and-replace of auto_ptr to unique_ptr; the vast majority of uses will work the same, and it might expose (as a compile-time error) or fix (silently) a bug or two you didn’t know you had.

另请注意,C++17 将删除 std::auto_ptr。

我认为可能有不同的方法来解决您的问题,“正确”的方法还取决于您实际代码的编写方式。
几个选项是:

选项 1

使用boost::unique_ptr

选项 2

根据__cplusplus有条件地使用auto_ptr或unique_ptr。

class Myclass {
#if __cplusplus < 201103L
std::auto_ptr m_ptr;
#else
std::unique_ptr m_ptr;
#endif
...

这个会散落在你引用的每个地方auto_ptr,我不太喜欢
如果您对 std::auto_ptr 的所有引用都已经进行了类型定义(只需有条件地更改类型定义),可能看起来不那么尴尬。

选项 3

有条件地使用 using 和别名来“定义”auto_ptr(并在没有 std:: 命名空间的情况下引用它)。

#if __cplusplus < 201103L
using std::auto_ptr;
#else
template
using auto_ptr = std::unique_ptr;
#endif

缺点:你继续使用“auto_ptr”,但在 c++11 中它意味着 std::unique_ptr。
真是一头雾水...

选项 3.1

可能略好于选项 2:
反向使用别名并更喜欢 unique_ptr name.

选项 4

将 std:: 智能指针(有条件地 auto_ptr 或 unique_ptr)包装在您自己定义的模板智能指针中 class.
这可能很麻烦,需要用新的 class.

搜索和替换所有 auto_ptr 引用

其他脏选项

其他选项涉及 std:: 命名空间内的定义,我认为这是标准禁止的,
或使用预处理器 #define 到 ...ehm...“重命名”unique_ptr 到 auto_ptr 仅适用于旧的 C++03 编译器。

如果我是认真的,我会创建一个 notstd 命名空间。

目标是在 C++11 中,notstd 包含一系列 std 类型的别名。在C++03中,它有伪C++11代码。

C++03 notstd 代码不会与 C++11 std 100% 兼容,而是有效的 C++03 notstd 会产生有效的C++11 行为。

例如,我可能会为 notstd::move 引用使用特殊标记的 "reference-wrapper" 类类型而不是右值引用,并且让我的仅移动类型需要这样标记的 "reference-wrapper"s。

namespace notstd {
  template<class U>
  struct moved_t {
    U& u;
    // relies on NRVO, which is pretty universally supported.
    // also relies in U being default-constructible:
    operator U()const{ U tmp; std::swap(u, tmp); return tmp; }
  };
  template<class U>
  moved_t<U> move(U& u) { return {u}; }
  template<class T>
  struct unique_ptr {
    unique_ptr( moved_t<unique_ptr<T>> > ); // move ctor
    template<class U>
    unique_ptr( moved_t<unique_ptr<U>> > ); // move ctor
  private:
    unique_ptr(unique_ptr const&);
  };
}

因此您的代码将使用 notstd::unique_ptr<T>。不会有隐式右值转换,所以你移动的每个地方 notstd::unique_ptr<T> 你都必须 notstd::move 它。

遗憾的是,这意味着 notstd::unique_ptr<T> 无法放入 std 容器中。可能需要进行一些破解才能使其正常工作(auto_ptr 也不能安全)。

这是一项非常重要的任务。 boost::unique_ptr 是在 C++03 中生成类似于 unique_ptr 的语义的尝试,它们将比您最有可能做得更好。如果您不能直接使用它们,请阅读它们所做的并自己重新实现它。