如何处理C ++ 11中auto_ptr弃用的设计更改?


12

我们正在测试C ++ 11(即-std=c++11)下的库。该库使用auto_ptr以下模式:

Foo* GetFoo()
{
    autoptr<Foo> ptr(new Foo);

    // Initialize Foo
    ptr->Initialize(...);

    // Now configure remaining attributes
    ptr->SomeSetting(...);

    return ptr.release();
}

C ++ 11已弃用auto_ptr,因此我们希望远离它。

但是,该代码同时支持C ++ 03和C ++ 11,因此它不是yanking那样简单auto_ptr。还值得一提的是该库没有外部依赖项。它使用C ++ 03; 并且不使用Autotools,Cmake,Boost等

auto_ptr在保持与C ++ 03的兼容性的同时,我们应如何处理设计更改以脱离C ++ 11?


是否有任何auto_ptr作用域(即std::auto_ptr),它们是否需要存在,还是可以从其他名称空间获取智能指针?
Niall

顺便说一句,你可能要折叠Foo::InitializeFoo::Foo
MSalters

1
@MSalters-是的,这一直是我感到有些不舒服的事情之一。该库是在1990年代设计的,我认为设计类似于MFC。也就是说,存在较低级别的C ++构造,然后是“较高级别”的对象构造。我认为该功能只是一种折衷,因此类没有6或12个不同的构造函数。(到此为止,我已经完成了所有工作,并确保在C ++构造函数中将POD类型的成员变量初始化为合理的默认值)。

Answers:


13

在大多数方面,它std::unique_ptr是可以替代(但更安全)的替代方法std::auto_ptr,因此,除了(如您要求的那样)指示代码使用unique_ptr或之外,几乎不需要(如果有的话)进行代码更改auto_ptr

下面有几种方法可以做到这一点(每种方法都有自己的列表折衷)。给定提供的代码示例,我希望使用前两个选项之一

选项1

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

权衡;

  • 您将auto_ptr名称引入全局名称空间;您可以通过定义它是您自己的“私有”名称空间来减轻这种情况
  • 一旦迁移到C ++ 17(我相信auto_ptr它将被完全删除),您可以更轻松地搜索和替换

选项2

template <typename T>
struct my_ptr {
    #if __cplusplus >= 201103L
    typedef std::unique_ptr<T> ptr;
    #else
    typedef std::auto_ptr<T> ptr;
    #endif
};

权衡;

  • 使用起来可能比较麻烦,目前所有auto_ptr需要将代码更改为类似my_ptr<T>::ptr
  • 更好的安全性,不会将名称引入全局名称空间

选项3

颇有争议,但如果您准备忍受以std阶级为基础的警告

#if __cplusplus >= 201103L
template <typename T>
using my_ptr = std::unique_ptr<T>;
#else
template <typename T>
class my_ptr : public std::auto_ptr<T> {
  // implement the constructors for easier use
  // in particular
  explicit my_ptr( X* p = 0 ) : std::auto_ptr(p) {}
};
#endif

权衡;

  • 不要在期望有虚拟基础(尤其是非虚拟析构函数)的地方使用继承的类。并不是说这应该是一个问题-但请注意
  • 再次,代码更改
  • 潜在的名称空间不匹配-这完全取决于如何使用指针类开始

选项4

将指针包装在新类中,并将所需的函数聚合到成员

template <typename T>
class my_ptr { // could even use auto_ptr name?
  #if __cplusplus >= 201103L
  std::unique_ptr<T> ptr_;
  #else
  std::auto_ptr<T> ptr_;
  #endif

  // implement functions required...
  T* release() { return ptr_.release(); }
};

权衡;

  • 当您真正想要的只是“交换”实现时,有点极端

很好的答案。我实际上进行了一些研究,您至少打了我尝试过的三个测试。(您缺少的是OS X和Clang特定的东西。OS X是熊,因为它有时仍在C ++ 03上使用TR1命名空间,并且您必须使用此方法包括一些内容:命名空间中没有名为“ unique_ptr”的类型在LLVM / Clang下编译时为“ std”

@jww。我在OS X(XCode 6.4和Apple LLVM版本6.1.0(clang-602.0.53)(基于LLVM 3.6.0svn))上,除了tr1名称空间外,C ++ 03/11混合没有问题不再在那里(我确实使用libc ++而不是libstdc ++)。我知道tr1是非规范性的,但是在草稿中(这里)根本找不到文件<tr1/...>,实际上它只是在标头等<memory>文件中,只是在tr1名称空间中。
Niall,2015年

@jww。我猜想,考虑到编译器,库和目标设备的特定组合,您可能需要再做一些手动操作。另外,在OS X上,请考虑使用clang和libc ++。坦率地说,我认为libc ++是OS X的新“本机” C ++库-我会默认使用它。除了clang / Apple关系的历史以及OS X上的GCC工具似乎已经过时(库)或刚刚删除(据我所知,GCC无论如何都是clang而言,它都是很薄的存根),我都无法支持这些说法。 )。
Niall,2015年

“否则,在OS X上,请考虑使用clang和libc ++ ...” -是的,我有点同意你的看法。但是,我们希望让用户做出选择,而不是强加于他们。(他们在指定(或缺少)时隐式做出选择CXX=...)。

下面是引起了我这么多的麻烦就OS X 10.7和10.8的情况:c++ -v -std=c++11 -x c++ - < /dev/null。我grep'd包含已转储的include目录,但包含unique_ptr

0

选项5:直接别名。

#if __cplusplus >= 201103L
template<typename T> 
using MyPtr = std::unique_ptr<T>;
#else 
#define MyPtr std::auto_ptr
#endif 

权衡:

  1. 对于AKA C ++ 11和更高版本的较新语言版本,您的别名类型将映射到正确的智能指针。任何实际上依赖于std :: auto_ptr特定的API的用户代码都将被编译器标记,这是对其进行真正修复的最终保证。

  2. 在传统c ++ 03模式下,类型别名是宏。这很繁琐,但是MyPtr<T>在其余的代码中,所得语法与C ++ 11情况相同。

  3. 您必须找到并更改所有auto_ptr变量MyPtr才能进行设置。


1
目前尚不清楚它指的是什么(从字面上讲,这根本不是问题)。
autophage

1
@autophage我相信它是一个答案...所以可能不是一个问题。
Kain0_0
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.