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:
- 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 的语义的尝试,它们将比您最有可能做得更好。如果您不能直接使用它们,请阅读它们所做的并自己重新实现它。
我正在尝试更新一些 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:
- 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.
其他脏选项
其他选项涉及 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 的语义的尝试,它们将比您最有可能做得更好。如果您不能直接使用它们,请阅读它们所做的并自己重新实现它。