为什么auto_ptr被弃用?

105

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

另外,我想知道auto_ptrshared_ptr的区别。


可能是auto_ptr已被弃用?的重复问题。 - malat
5个回答

100
直接替换auto_ptr(或最接近的替代品)的是unique_ptr。就“问题”而言,它相当简单:auto_ptr在被分配时转移所有权。unique_ptr也会转移所有权,但由于移动语义的规范化以及右值引用的神奇之处,可以更自然地进行转移。 它也与标准库的其他部分更加“匹配”(尽管公平地说,其中一些要归功于库的其余部分改变以适应移动语义而不总是需要复制)。
名称的更改也很受欢迎——auto_ptr对尝试自动化的内容并没有提供太多信息,而unique_ptr则是对所提供内容的一个相当合理(虽然简洁)的描述。

26
关于auto_ptr名称的注解:auto暗示了自动变量,它指的是auto_ptr所做的一件事情:在其析构函数中(当其超出作用域时)销毁管理资源。 - Vincenzo Pii
18
进一步信息:这里是废弃auto_ptr的官方原因:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1856.html#20.4.5%20-%20Class%20template%20auto_ptr - Howard Hinnant
@HowardHinnant 有趣的文档!从某种意义上说,如果std::sort()有一个专门为std::unique_ptr设计的特化版本来根据需要使用移动语义,那么这是奇怪的。我想知道为什么std::sort()不能为std::auto_ptr进行特化以纠正文档中提到的复制问题。提前致谢。 - Hei
3
@Hei:std::sort没有针对unique_ptr的特化。相反,它被重新指定为永远不会复制。因此,现代的sort实际上可以使用auto_ptr。但是C++98/03的sort只是这里的一个示例算法:任何假定复制语法具有复制语义的通用算法(std提供的或用户编写的)如果与auto_ptr一起使用,可能会导致运行时错误,因为auto_ptr使用复制语法静默地移动。这个问题比sort大得多 - Howard Hinnant

37
I found the existing answers great, but from the PoV of the pointers. IMO, an ideal answer should have the user/programmer's perspective answer.
First thing first (as pointed by Jerry Coffin in his answer)
- auto_ptr could be replaced by shared_ptr or unique_ptr depending upon situation
shared_ptr: If you are concerned about freeing of resource/memory AND if you have more than one function that could be using the object AT-DIFFERENT times, then go with shared_ptr.
By DIFFERENT-Times, think of a situation where the object-ptr is stored in multiple data-structure and later accessed. Multiple threads, of course is another example. unique_ptr: If all you are concerned is freeing memory, and the access to object is SEQUENTIAL, then go for unique_ptr.
By SEQUENTIAL, I mean, at any point object will be accessed from one context. E.g. a object that was created, and used immediately after creation by the creator. After creation the object is stored in FIRST data-structure. Then either the object is destroyed after the ONE data-structure or is moved to SECOND data-structure.
从这一行开始,我将把shared/unique_ptr称为智能指针。(auto_ptr也是智能指针,但由于其设计上的缺陷,因为它们已经被弃用,在下一行中我将指出这些缺陷,所以它们不应该与智能指针分组。)
单个最重要的原因,使auto_ptr被弃用并采用智能指针是赋值语义。如果没有这个原因,他们本可以将所有新的移动语义功能添加到auto_ptr中,而不是将其弃用。由于赋值语义是最不受欢迎的特性,他们希望这个特性消失,但由于存在使用该语义的代码(标准委员会无法更改),他们不得不放弃auto_ptr,而不是修改它。
来自链接:http://www.cplusplus.com/reference/memory/unique_ptr/operator=/ unique_ptr支持的赋值类型
  • 移动赋值 (1)
  • 赋空指针 (2)
  • 类型转换赋值 (3)
  • 复制赋值(已删除!)(4)

来源:http://www.cplusplus.com/reference/memory/auto_ptr/operator=/

auto_ptr支持的赋值类型

  • 复制赋值 (4) 罪魁祸首

现在来谈谈为什么复制赋值本身如此不受欢迎,我有这个理论:

  1. 并非所有程序员都读书或标准。
  2. auto_ptr表面上承诺您拥有该对象的所有权。
  3. auto_ptr的小星号(意图),并非所有程序员都会阅读,允许将一个auto_ptr分配给另一个auto_ptr,并转移所有权。
  4. 研究表明,此行为仅适用于3.1415926535%的所有使用情况,并且在其他情况下是无意的。

不良行为真的不受欢迎,因此不喜欢auto_ptr。

(对于那些刻意想要转移C++11赋予的所有权std::move()的3.1415926536%程序员,这使得他们的意图对于将来阅读和维护代码的实习生变得非常明确。)

1
由于您永远不希望两个指向同一对象的auto_ptr值(因为它们不提供共享所有权,第一个死亡的将使另一个留下致命遗产;这也适用于unique_ptr使用), 您能建议在剩余96.8584073465%的所有用法中打算使用什么吗? - Marc van Leeuwen
我不能代表全部,但我猜他们会认为对象所有权正在被“移动”,而不仅仅是被复制,这是错误的。 - Ajeet Ganga
@AjeetGanga你提到了auto_ptr的小技巧,它不被所有程序员所知,允许将一个auto_ptr分配给另一个并转移所有权。假设我有两个指向整数的auto_ptr,a和b。我执行的赋值是*a=*b;这里只是将b的值复制到a中。我希望a和b的所有权仍然属于同一人。你提到了所有权将被转移。那么它会是怎样的呢? - VINOTH ENERGETIC
@VINOTHENERGETIC Ajeet正在谈论将auto_ptr对象分配给自身。对/从其指向的值进行分配对所有权没有影响或相关性。我希望你现在不再使用auto_ptr了? - underscore_d
@underscore_d 明白了。我现在没有使用共享指针,只是出于好奇想要理解这个概念。 - VINOTH ENERGETIC
显示剩余3条评论

24

shared_ptr可以存储在容器中,auto_ptr则不行。

顺便说一句,unique_ptr 真正是 auto_ptr 的直接替代品,它结合了 std::auto_ptrboost::scoped_ptr 的最佳特点。


13
另一种解释差异的方法....
从功能上讲,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成员,则复制实例会从被复制的实例中释放指针:这是一种奇怪和危险的混淆语义,因为通常复制不会修改原实例。当类/结构的作者在推理不变量和状态时容易忽略指针的释放,因此意外地尝试在空指针上解引用智能指针,或者仅仅没有对指向数据的访问/所有权进行预期。

auto_ptr 悄悄地“窃取”所有权 +1 - camino

5

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接