【发布时间】:2011-04-11 11:50:06
【问题描述】:
我听说auto_ptr 在 C++11 中已被弃用。这是什么原因?
我也想知道auto_ptr和shared_ptr之间的区别。
【问题讨论】:
标签: c++ c++11 smart-pointers auto-ptr
我听说auto_ptr 在 C++11 中已被弃用。这是什么原因?
我也想知道auto_ptr和shared_ptr之间的区别。
【问题讨论】:
标签: c++ c++11 smart-pointers auto-ptr
另一种解释差异的方法......
从功能上讲,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 不能在 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
【讨论】:
我发现现有的答案很好,但来自指针的 PoV。 IMO,一个理想的答案应该有用户/程序员的观点答案。
第一件事(正如 Jerry Coffin 在他的回答中指出的那样)
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 支持的赋值类型
发件人:http://www.cplusplus.com/reference/memory/auto_ptr/operator=/
auto_ptr 支持的分配类型
现在谈到为什么复制作业本身如此不受欢迎的原因,我有这个理论:
不喜欢这种意外行为,因此不喜欢 auto_ptr。
(对于有意转移所有权的 3.1415926536% 的程序员,C++11 给了他们 std::move(),这让所有打算阅读和维护代码的实习生清楚地知道他们的意图。 )
【讨论】:
auto_ptr值(因为它们不提供共享所有权,第一个死掉的会留下另一个致命的遗产;unique_ptr 的使用情况也是如此),您能否建议在剩余的 96.8584073465% 的使用情况中是什么?
*a=*b; 的身份进行分配,这里只有 b 的值被复制到 a。我希望 a 和 b 的所有权仍然属于同一个人。您提到的所有权将被转移。会怎么样?
auto_ptr 对象本身。分配给/从其指向的值对所有权没有影响,也与所有权无关。我希望你还没有使用auto_ptr?
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/…
std::sort 没有unique_ptr 的专业化。相反,它被重新指定为从不复制。所以auto_ptr 实际上确实 与现代sort 一起工作。但是 C++98/03 sort 只是这里的一个示例算法:Any 假设复制语法具有复制语义的通用算法(标准提供或用户编写)可能会运行如果与auto_ptr 一起使用,则-time 错误,因为auto_ptr 以copy 语法静默移动。这个问题比sort大得多。
shared_ptr 可以存储在容器中。 auto_ptr不能。
顺便说一句,unique_ptr 确实是直接的auto_ptr 替代品,它结合了std::auto_ptr 和boost::scoped_ptr 的最佳功能。
【讨论】: