【问题标题】:Why is auto_ptr being deprecated?为什么不推荐使用 auto_ptr?
【发布时间】:2011-04-11 11:50:06
【问题描述】:

我听说auto_ptr 在 C++11 中已被弃用。这是什么原因?

我也想知道auto_ptrshared_ptr之间的区别。

【问题讨论】:

标签: c++ c++11 smart-pointers auto-ptr


【解决方案1】:

另一种解释差异的方法......

从功能上讲,C++11 的 std::unique_ptr 是“固定的”std::auto_ptr:它们都适用于 - 在执行期间的任何时间点 - 应该有一个智能指针所有者用于指向对象。

关键的区别在于从另一个未过期的智能指针复制构造或赋值,如下面的=> 行所示:

   std::auto_ptr<T> ap(new T{...});       // OK - alloc/construct, up owns
   ...or...
   std::auto_ptr<T> ap(get_ap_to_T());   // OK - take expiring ownership

   ...then...
=> std::auto_ptr<T> ap2(ap);  // take un-expiring ownership ala ap3(ap.release());
   ap->xyz;  // oops... tried to use ap, expecting it to be non-NULL

   // --------------------------------------------------------------

   std::unique_ptr<T> up(new T{...});       // OK - alloc/construct, up owns
   ...or...
   std::unique_ptr<T> up = std::make_unique<T>(...);       // OK too
   ...or...
   std::unique_ptr<T> up(get_up_to_T());   // OK - take expiring ownership

   ...then...
=> std::unique_ptr<T> up2(up);  // COMPILE ERROR: can't take un-expiring ownership
=> std::unique_ptr<T> up2(std::move(up));  // EXPLICIT code allowed
=> std::unique_ptr<T> up2(up.release());   // EXPLICIT code allowed

上面,ap3 auto_ptr 悄悄地“窃取”*ap 的所有权,将ap 设置为nullptr,问题是这很容易发生,程序员没有考虑过它的安全性。

例如,如果class/struct 有一个std::auto_ptr 成员,那么复制一个实例将release 指向被复制实例的指针:这与通常复制一样奇怪且危险地混淆语义有些东西不会修改它。类/结构作者在推理不变量和状态时很容易忽略指针的释放,因此在 null 时不小心尝试取消引用智能指针,或者只是仍然没有预期的指向数据的访问/所有权。

【讨论】:

  • auto_ptr 悄悄“窃取”所有权 +1
【解决方案2】:

auto_ptr 不能在 STL 容器中使用,因为它的复制构造函数不符合容器 CopyConstructible 的要求。 unique_ptr 不实现复制构造函数,因此容器使用替代方法。 unique_ptr 可以在容器中使用,并且对于 std 算法比 shared_ptr 更快。

#include <iostream>
#include <type_traits>
#include <vector>
#include <memory>

using namespace std;

int main() {
  cout << boolalpha;
  cout << "is_copy_constructible:" << endl;
  cout << "auto_ptr: " << is_copy_constructible< auto_ptr<int> >::value << endl;
  cout << "unique_ptr: " << is_copy_constructible< unique_ptr<int> >::value << endl;
  cout << "shared_ptr: " << is_copy_constructible< shared_ptr<int> >::value << endl;

  vector<int> i_v;
  i_v.push_back(1);
  cout << "i_v=" << i_v[0] << endl;
  vector<int> i_v2=i_v;
  cout << "i_v2=" << i_v2[0] << endl;

  vector< unique_ptr<int> > u_v;
  u_v.push_back(unique_ptr<int>(new int(2)));
  cout << "u_v=" << *u_v[0] << endl;
  //vector< unique_ptr<int> > u_v2=u_v;  //will not compile, need is_copy_constructible == true
  vector< unique_ptr<int> > u_v2 =std::move(u_v);  // but can be moved
  cout << "u_v2=" << *u_v2[0] << " length u_v: " <<u_v.size() << endl;

  vector< shared_ptr<int> > s_v;
  shared_ptr<int> s(new int(3));
  s_v.push_back(s);
  cout << "s_v=" << *s_v[0] << endl;
  vector< shared_ptr<int> > s_v2=s_v;
  cout << "s_v2=" << *s_v2[0] << endl;

  vector< auto_ptr<int> > a_v;  //USAGE ERROR

  return 0;
}

>cxx test1.cpp -o test1
test1.cpp: In function âint main()â:
test1.cpp:33:11: warning: âauto_ptrâ is deprecated (declared at /apps/hermes/sw/gcc/gcc-4.8.5/include/c++/4.8.5/backward/auto_ptr.h:87) [-Wdeprecated-declarations]
   vector< auto_ptr<int> > a_v;  //USAGE ERROR
           ^
>./test1
is_copy_constructible:
auto_ptr: false
unique_ptr: false
shared_ptr: true
i_v=1
i_v2=1
u_v=2
s_v=3
s_v2=3

【讨论】:

    【解决方案3】:

    我发现现有的答案很好,但来自指针的 PoV。 IMO,一个理想的答案应该有用户/程序员的观点答案。

    第一件事(正如 Jerry Coffin 在他的回答中指出的那样)

    • auto_ptr 可以根据情况替换为 shared_ptr 或 unique_ptr

    shared_ptr :如果您担心资源/内存的释放,并且如果您有多个函数可以使用对象 AT-DIFFERENT 次,那么请使用 shared_ptr。

    通过 DIFFERENT-Times,想想 object-ptr 存储在多个数据结构中并稍后访问的情况。多线程,当然是另一个例子。

    unique_ptr :如果您只关心释放内存,并且对对象的访问是连续的,那么选择 unique_ptr。

    按顺序,我的意思是,在任何时候都将从一个上下文访问对象。例如。由创建者创建并在创建后立即使用的对象。创建后,对象存储在 FIRST 数据结构中。然后对象要么在 ONE 数据结构之后被销毁,要么被移动到 SECOND 数据结构中。

    从这一行开始,我将共享/唯一_ptr 称为智能指针。 (auto_ptr 也是智能指针,但由于其设计存在缺陷,因此它们已被弃用,我想我将在下一行中指出,它们不应与智能指针分组。)

    为什么不推荐使用 auto_ptr 以支持智能指针的一个最重要的原因是 assignment-semantics 如果不是因为这个原因,他们会在 auto_ptr 中添加所有新的移动语义,而不是弃用它。由于赋值语义是最不喜欢的功能,他们希望该功能消失,但由于编写了使用该语义的代码(标准委员会无法更改),他们不得不放弃 auto_ptr,而不是修改它。

    来自链接:http://www.cplusplus.com/reference/memory/unique_ptr/operator=/

    unqiue_ptr 支持的赋值类型

    • 移动作业(1)
    • 分配空指针(2)
    • 类型转换赋值 (3)
    • 复制作业(已删除!)(4)

    发件人:http://www.cplusplus.com/reference/memory/auto_ptr/operator=/

    auto_ptr 支持的分配类型

    • 复制作业(4)罪魁祸首

    现在谈到为什么复制作业本身如此不受欢迎的原因,我有这个理论:

    1. 并非所有程序员都阅读书籍或标准
    2. 从表面上看,auto_ptr 承诺您拥有该对象的所有权
    3. auto_ptr 的 little-*(双关语)子句并非所有程序员都能阅读,它允许将一个 auto_ptr 分配给另一个 auto_ptr,并转移所有权。
    4. 研究表明,此行为适用于 3.1415926535 % 的所有使用情况,而在其他情况下则不会发生。

    不喜欢这种意外行为,因此不喜欢 auto_ptr。

    (对于有意转移所有权的 3.1415926536% 的程序员,C++11 给了他们 std::move(),这让所有打算阅读和维护代码的实习生清楚地知道他们的意图。 )

    【讨论】:

    • 因为你从不想要两个指向同一个对象的auto_ptr值(因为它们不提供共享所有权,第一个死掉的会留下另一个致命的遗产;unique_ptr 的使用情况也是如此),您能否建议在剩余的 96.8584073465% 的使用情况中是什么
    • 不能代表所有人,但我猜,他们会认为对象所有权正在移动,而不仅仅是复制,这是错误的。
    • @AjeetGanga 在下面的短语“the little-*(双关语)”中,您提到了“双关语”。这句话对我来说是新的,无论如何我用谷歌搜索它并知道这里有一些玩笑是故意的。这里开什么玩笑?只是想知道这一点。
    • @AjeetGanga 你提到了像'the little-*(双关语),auto_ptr 的子句,并非所有程序员都阅读,允许将一个 auto_ptr 分配给另一个,并转移所有权'。假设我有两个自动 ptr 作为整数的 a 和 b。我正在以*a=*b; 的身份进行分配,这里只有 b 的值被复制到 a。我希望 a 和 b 的所有权仍然属于同一个人。您提到的所有权将被转移。会怎么样?
    • @VINOTHENERGETIC Ajeet 正在谈论分配给 auto_ptr 对象本身。分配给/从其指向的值对所有权没有影响,也与所有权无关。我希望你还没有使用auto_ptr
    【解决方案4】:

    auto_ptr 的直接替代品(或者最接近的替代品)是unique_ptr。就“问题”而言,它非常简单:auto_ptr 在分配所有权时转移所有权。 unique_ptr 也转移所有权,但由于移动语义的编码和右值引用的魔力,它可以更自然地做到这一点。它也更好地“适合”标准库的其余部分(尽管公平地说,其中一些要归功于库的其余部分进行了更改以适应移动语义,而不是总是需要复制)。

    名称的更改也是 (IMO) 一个受欢迎的更改 -- auto_ptr 并没有真正告诉您它尝试自动化的内容,而 unique_ptr 是对所提供内容的相当合理(如果简洁的话)的描述.

    【讨论】:

    • 只是在 auto_ptr 名称上的注释: auto 建议自动作为自动变量,它指的是 auto_ptr 做的一件事:在其析构函数中销毁托管资源(当它熄灭时)范围)。
    • 更多信息:这是弃用auto_ptr的官方理由:open-std.org/jtc1/sc22/wg21/docs/papers/2005/…
    • @HowardHinnant 有趣的文档!在某种意义上奇怪的是,如果 std::sort() 具有 std::unique_ptr 的特化,可以根据需要使用移动语义。我想知道为什么 std::sort() 不能专门用于 std::auto_ptr 来纠正文档中提到的复制问题。提前致谢。
    • @Hei: std::sort 没有unique_ptr 的专业化。相反,它被重新指定为从不复制。所以auto_ptr 实际上确实 与现代sort 一起工作。但是 C++98/03 sort 只是这里的一个示例算法:Any 假设复制语法具有复制语义的通用算法(标准提供或用户编写)可能会运行如果与auto_ptr 一起使用,则-time 错误,因为auto_ptrcopy 语法静默移动。这个问题sort大得多
    【解决方案5】:

    shared_ptr 可以存储在容器中。 auto_ptr不能。

    顺便说一句,unique_ptr 确实是直接的auto_ptr 替代品,它结合了std::auto_ptrboost::scoped_ptr 的最佳功能。

    【讨论】:

      猜你喜欢
      • 2011-01-25
      • 1970-01-01
      • 2016-02-23
      • 2017-11-04
      • 2011-10-22
      • 2021-10-12
      • 2012-12-07
      • 2012-05-16
      • 2020-06-29
      相关资源
      最近更新 更多