我正在尝试更新一些 C++ 代码,我想转向更现代的代码(c++11),但我仍然需要使用一些较旧的编译器(兼容 c++03)来编译代码,因为支持的平台限制。
我知道在 C++11 编译器中 std::auto_ptr 已被弃用,但由于较旧的编译器支持,我不能只用 std::unique_ptr 替换它们。
是否有一个好的做法来处理这种“旧编译器支持,但开始转向 C++11”?
正如您所指出的,std::auto_ptr<> 在 C++11 中已被弃用 (参考)。
转向 c++11 std::unique_ptr<> 是正确的方法,正如 Herb Sutter 在 得到W89:
- auto_ptr 是怎么回事?
auto_ptr 最仁慈的特征是在 C++ 拥有移动语义之前创建 unique_ptr 的勇敢尝试。 auto_ptr 现已弃用,不应在新代码中使用。
如果现有代码库中有 auto_ptr,当您有机会时尝试将 auto_ptr 全局搜索并替换为 unique_ptr;绝大多数用途都将工作相同,并且它可能会暴露(作为编译时错误)或修复(默默地)一两个您不知道的错误。
另请注意,C++17 将删除 std::auto_ptr。
我认为解决您的问题可能有不同的方法,“正确”的方法还取决于您的实际代码是如何编写的。
几个选项是:
使用 boost::unique_ptr
有条件地使用基于__cplusplus的auto_ptr或unique_ptr。
我的班级{
#if __cplusplus < 201103L
std::auto_ptr m_ptr;
#其他
std::unique_ptr m_ptr;
#结束
...
这会分散在你引用auto_ptr的每个地方,我不太喜欢它。
如果您对 std::auto_ptr 的所有引用都已经进行了类型定义(只需有条件地更改类型定义),可能看起来就不那么尴尬了。
有条件地使用 using 和别名来“定义”auto_ptr(并在没有 std:: 命名空间的情况下引用它)。
#if __cplusplus < 201103L
使用 std::auto_ptr;
#其他
模板
使用 auto_ptr = std::unique_ptr;
#结束
缺点:你继续使用“auto_ptr”,但在 c++11 中它意味着 std::unique_ptr。
真的很混乱...
可能比选项 3 稍好:
相反使用别名并更喜欢 unique_ptr 名称。
将 std:: 智能指针(有条件地 auto_ptr 或 unique_ptr)包装在您自己定义的模板智能指针类中。
这可能很麻烦,需要搜索并用新类替换所有 auto_ptr 引用。
其他选项涉及 std:: 命名空间内的定义,我认为这是标准所禁止的,
或者使用预处理器 #define 来...呃...“重命名” unique_ptr 为 auto_ptr 仅适用于旧的 C++03 编译器。
在这种情况下,您可以使用
boost::unique_ptr
而不是 auto_ptr
来开始现代化代码,但不建议这样做。
总的来说,C++11 库的很大一部分是直接取自 boost,所以这将是一个很好的起点。
如果我是认真的,我会创建一个
notstd
命名空间。
目标是在 C++11 中,
notstd
由一系列 std
类型的别名组成。在C++03中,它有伪C++11代码。
C++03
notstd
代码不会 100% 与 C++11 std
兼容,但有效的 C++03 notstd
会反过来产生有效的 C++11 行为。
例如,我可能会使用特殊标记的“引用包装器”(例如
notstd::move
引用类型)而不是右值引用,并且我的仅移动类型需要此类标记的“引用包装器”。
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 的语义的尝试,并且它们很可能会比您做得更好。如果您无法直接使用它们,请阅读它们的用途并自己重新实现。