【问题标题】:C++ std:.auto_ptr or std::unique_ptr (to support multiple compilers, even old C++03 compilers)?C++ std:.auto_ptr 或 std::unique_ptr (支持多个编译器,甚至是旧的 C++03 编译器)?
【发布时间】:2016-11-30 16:40:03
【问题描述】:

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

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

是否有处理这种“旧的编译器支持,但开始转向 C++11”的好习惯?

【问题讨论】:

    标签: c++ c++11 smart-pointers c++03


    【解决方案1】:

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

    移至 c++11 std::unique_ptr 是正确的方法,正如 Herb Sutter 在 GotW89:

    1. 与 auto_ptr 有什么关系?
      auto_ptr 最慷慨地描述为在 C++ 具有移动语义之前创建 unique_ptr 的勇敢尝试。 auto_ptr 现已弃用,不应在新代码中使用。
      如果您在现有代码库中有 auto_ptr,当您有机会尝试将 auto_ptr 全局搜索并替换为 unique_ptr 时;绝大多数用途都是一样的,它可能会暴露(作为编译时错误)或修复(默默地)一两个你不知道的错误。

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

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

    选项 1

    使用 boost::unique_ptr

    选项 2

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

    类 Myclass {
    #if __cplusplus std::auto_ptr m_ptr;
    #其他
    std::unique_ptr m_ptr;
    #endif
    ...

    这将分散在您引用 auto_ptr 的每个地方,我不太喜欢它。
    如果您对 std::auto_ptr 的所有引用都已经被 typedef 了(只是有条件地更改 typedef),那么可能看起来不那么尴尬。

    选项 3

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

    #if __cplusplus 使用 std::auto_ptr;
    #其他
    模板
    使用 auto_ptr = std::unique_ptr;
    #endif

    缺点:你一直在使用“auto_ptr”,但在 c++11 中它意味着 std::unique_ptr。
    真是迷惑……

    选项 3.1

    可能比选项 2 略好:
    使用别名进行反向,并首选 unique_ptr 名称。

    选项 4

    将 std:: 智能指针(条件为 auto_ptr 或 unique_ptr)包装在您自己定义的模板智能指针类中。
    这可能很麻烦,需要使用新类搜索和替换所有 auto_ptr 引用。

    其他脏选项

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

    【讨论】:

    • 伟大而完整的答案。 Boost 很诱人,但我也有限制(试图)避免它。请不要问,约束不是我定义的:-(。
    • @roalz: "C++17 肯定会删除 std::auto_ptr" 它“可能”什么都不做。 auto_ptr is 正在从 C++17 中删除。虽然是的,但委员会有可能决定不这样做,但目前他们不太可能这样做。
    • 我相信如果您以有效的auto_ptr 代码开头并将其替换为unique_ptr,则代码会中断,反之亦然。
    • 约束是特定于 Boost 的,还是包含所有“第三方库”的?我写了一个backports library for C++03 (and others),其中包括unique_ptr,如果您不能只获取库,文档中提到了您可以用作基础的Howard Hinnart 的早期实现。在 C++03 模式下不会让你一切(根据定义,它不能),但它应该让你达到可用和更高的水平。
    【解决方案2】:

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

    总体而言,C++11 库的很大一部分是直接从 boost 中获取的,因此它将是一个很好的起点。

    【讨论】:

    • 不幸的是,我也有限制(尝试)不使用 Boost(对不起,他们没有决定权!)
    【解决方案3】:

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

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

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

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

    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&lt;T&gt;。不会有隐式的右值转换,所以你移动notstd::unique_ptr&lt;T&gt; 的每个位置都必须notstd::move 它。

    遗憾的是,这意味着 notstd::unique_ptr&lt;T&gt; 不能放入 std 容器中。可能必须进行一些 hack 才能使其正常工作(auto_ptr 也不能安全)。

    这是一项不平凡的任务。 boost::unique_ptr 试图在 C++03 中生成类似 unique_ptr 的语义,而且它们会比你很可能做得更好。如果您不能直接使用它们,请阅读它们的作用并自己重新实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-07
      • 1970-01-01
      • 2021-05-21
      • 2016-05-01
      • 2014-05-12
      • 1970-01-01
      • 1970-01-01
      • 2015-07-23
      相关资源
      最近更新 更多