智能指针是什么
C++ libraries provide implementations of smart pointers in following types:
- auto_ptr
- unique_ptr
- shared_ptr
- weak_ptr
They all are declared in a memory header file.
在计算机科学中,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。
C++这类没有垃圾回收机制的语言时,你很多时间都花在处理如何正确释放内存上。如果程序运行时间足够长,如后台进程运行在服务器上,只要服务器不宕机就一直运行,一个小小的失误也会对程序造成重大的影响,如造成某些关键服务失败。
详情参考内存泄漏有什么后果
图转自https://www.geeksforgeeks.org/auto_ptr-unique_ptr-shared_ptr-weak_ptr-2/
auto_ptr
auto_ptr是一个智能指针,它管理通过新表达式获得的对象,并在销毁auto_ptr本身时删除该对象。当使用auto_ptr类描述对象时,它存储指向单个已分配对象的指针,这确保了当它超出范围时,它指向的对象必须自动销毁。它基于专有所有权模型,即相同类型的两个指针不能同时指向同一资源。如后续程序所示,指针的复制或分配会更改所有权,即源指针必须将所有权赋予目标指针。
复制构造函数和auto_ptr的赋值运算符实际上并不复制存储的指针,而是将其转移,将第一个auto_ptr对象留空。这是实现严格所有权的一种方法,因此在任何给定时间只有一个auto_ptr对象可以拥有该指针,即在需要复制语义的地方不应该使用auto_ptr。
为什么auto_ptr deprecated?
它以没有两个指针都不应包含同一对象的方式获取指针的所有权。分配会转移所有权,并将右值自动指针重置为空指针。因此,由于上述无法复制,因此无法在STL容器中使用它们。
比较尴尬的是,在容器使用auto_ptr也不会报错,因为其已经实现了复制构造函数与赋值运算符,尽管这种“严格所有权的复制”不是传统意义上的“复制赋值”,auto_ptr常常会导致一些莫名的错误(例如EXC_BAD_ACCESS);
后文将结合代码说明
unique_ptr
C ++ 11引入std :: unique_ptr,替代了std :: auto_ptr。 unique_ptr是一种具有类似功能的新设施,但具有改进的安全性(无伪造副本分配),增加的功能(deleters)和对arrays的支持。它是原始指针的容器。它显式地防止了其包含的指针的复制,这与普通分配会发生的情况相同,即它只允许基础指针的一个所有者。因此,当使用unique_ptr时,任何一种资源最多只能有一个unique_ptr,并且当该unique_ptr被销毁时,该资源将被自动释放。同样,由于任何资源只能有一个unique_ptr,因此任何尝试复制unique_ptr的尝试都会导致compile time error
unique_ptr<A> ptr1 (new A);
// Error: can't copy unique_ptr
unique_ptr<A> ptr2 = ptr1;
But, unique_ptr can be moved using the new move semantics i.e. using std::move() function to transfer ownership of the contained pointer to another unique_ptr.
// Works, resource now stored in ptr2
unique_ptr<A> ptr2 = move(ptr1);
因此,当我们想要指向对象的单个指针,而该对象在销毁后将被回收时,最好使用unique_ptr
shared_ptr与weak_ptr的参考链接
代码
#include <iostream>
#include <type_traits>
#include <vector>
#include <memory>
#include <exception>
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;
cout << "weak_ptr: " << is_copy_constructible< weak_ptr<int> >::value << endl;
cout << "is_copy_assignable:" << endl;
cout << "auto_ptr: " << is_copy_assignable< auto_ptr<int> >::value << endl;
cout << "unique_ptr: " << is_copy_assignable< unique_ptr<int> >::value << endl;
cout << "shared_ptr: " << is_copy_assignable< shared_ptr<int> >::value << endl;
cout << "weak_ptr: " << is_copy_assignable< weak_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
a_v.emplace_back(new int(999));
vector< auto_ptr<int> > a_v2=a_v;
// cout << "a_v=" << *a_v[0] << endl;
cout << "a_v2=" << *a_v2[0] << endl;
}
输出如下:
is_copy_constructible:
auto_ptr: false
unique_ptr: false
shared_ptr: true
weak_ptr: true
is_copy_assignable:
auto_ptr: false
unique_ptr: false
shared_ptr: true
weak_ptr: true
i_v=1
i_v2=1
u_v=2
u_v2=2 length u_v: 0
s_v=3
s_v2=3
a_v2=999
Program ended with exit code: 0
参考链接
https://www.geeksforgeeks.org/auto_ptr-unique_ptr-shared_ptr-weak_ptr-2/