1. 1. auto_ptr:源自于C++98的老大哥
  2. 2. unique_ptr:auto_ptr的优秀继承者
  3. 3. shared_ptr:允许多个指针指向同一个对象
  4. 4. weak_ptr:和shared_ptr通力合作的亲密友指针(其实也不能说是个智能指针)

一般来说,C++中一共有4种智能指针,包括引入于C++98的auto_ptr,以及引入于C++11的unique_ptr/shared_ptr/weak_ptr

auto_ptr:源自于C++98的老大哥

信息 说明
引入于 C++98
定义于 <memory>
优点 当指针对象被销毁时,它所管理的对象也会自动被delete掉
缺点 让我们在下面慢慢说
创建方法 auto_ptr ap(new string(“this is an auto_ptr”));
支持 拷贝构造,有参构造,无参构造

开始慢慢说吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>
#include<memory>
#include<vector>
using namespace std;

int main()
{
string *p=new String("This is a auto_ptr");
auto_ptr<string> p1(p);
auto_ptr<string> p2(p);
//禁忌1:禁止让两个auto_ptr指向同一片内存
//否则,在p1销毁后,p2会成为野指针,你也不想你指针乱指的事情被主管知道吧
auto_ptr<string> p3(p);
auto_ptr<string> p4(p3);
cout<<*p3;
//禁忌2:拷贝构造后调用原指针
//拷贝构造时会发生所有权转移,p3在p4构造后成为了空指针
//🎵爱上一个不存在的人🎵
int pp[10]={0};
auto_ptr<int> p5(pp);
//禁忌3:禁止指向数组
//auto_ptr在销毁所管理对象的时候会调用delete,但是销毁数组需要用delete[]
vector<int> pi;
vector.push_back(1);
vector.push_back(2);
vector.push_back(3);
auto_ptr<vector<int>> p6=&pi[0];
//禁忌4:禁止在容器相关的操作中调用auto_ptr
//auto_ptr是独占的,对其进行修改操作易发生所有权转移
}

unique_ptr:auto_ptr的优秀继承者

信息 说明
引入于 C++11
定义于 <memory>
优点 相对于auto_ptr来说,更加安全
创建方法 unique_ptr ap(new string(“this is an unique_ptr”));
支持 有参构造,无参构造,拷贝构造

在auto_ptr中,虽然也有所有权的定义,但如果使用有参构造,,同一个对象仍然可以由多个不同的auto_ptr共享,因此也就造成了同一片内存空间可能被多次释放/释放后调用,调用空指针等UB类问题
但对在unique_ptr中,加强了所有权,一个对象只可以由一个unique_ptr进行独享,所有权可以被释放,可以被转移,但绝不能被共享,因此弥补了auto_ptr的一些缺陷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iostream>
#include<memory>
#include<vector>
using namespace std;

int main()
{
unique_ptr<string> up1;
up1.reset(new string("This is an unique_ptr"));//使用reset绑定对象
unique_ptr<string> up2(new string("unique_ptr2"));//
unique_ptr<string> up3;
string *p=up1.release();
//使用release使up1释放对象所有权,并返回该对象于p指针
up3=move(up2);//使用[移动语义]()进行所有权转移;
up4.reset(up3.release());//up3释放所有权,up4绑定对象
up2.reset();//对象被销毁,指针变为空
up4=nullptr;//对象被销毁,指针变为空

//当且仅当unique_ptr为右值时,支持拷贝
unique_ptr get(){
unique_ptr<int> temp(new int(3));
return temp;
}
unique_ptr<int> gotit=get();
//此时gotit会接住get()函数返回的右值,由gotit指向get()函数中temp指针初始化的int对象

}

shared_ptr:允许多个指针指向同一个对象

信息 说明
引入于 C++11
定义于 C++11后:<memory> C++11前:Boost库
优点 相对于unique_ptr来说,允许多指针指向同一对象,且安全
创建方法 shared_ptr sp(new string(“this is an unique_ptr”));
支持 有参构造,无参构造,拷贝构造

在shared_ptr中,引入了”计数器”这一概念,当多个指针指向同一个对象时,这些指针共享同一个计数器,记录着改对象被引用的次数,当指针被销毁时,计数器会同步减少,当计数器减少到0时,该对象会被自动销毁
但是注意,shared_ptr在指针是线程不安全的,因此在涉及到修改等操作时需要加锁(mutex)

weak_ptr:和shared_ptr通力合作的亲密友指针(其实也不能说是个智能指针)

信息 说明
引入于 C++11
定义于 C++11后:<memory> C++11前:Boost库
优点 相对于unique_ptr来说,允许多指针指向同一对象,且安全
创建方法 shared_ptr sp(new string(“this is an unique_ptr”));
支持 无参构造,有参构造,拷贝构造
特性 可以弱引用shared_ptr且不会增加计数器计数

该指针被设计成和shared_ptr共同使用,可以用于观测shared_ptr目前的状态或对shared_ptr指向的对象进行一些操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<memory>
#include<vector>
using namespace std;

int main()
{
shared_ptr<string> sp1(new string("This is an unique_ptr"));
weak_ptr<string> wp(up1);
//使用拷贝构造实例化了一个weak_ptr指针
cout<<wp.use_count();
//打印up1的引用计数
cout<<wp.expired();
//检查是否存在,如果为1,则up1指向的对象已经不复存在
string *p=wp.lock();
//从wp指向的shared_ptr中获取其指向的对象,从而在不影响计数器的情况下进行操作
//此时sp1的计数器不会+1,如果sp1为空,会返回一个空的shared_ptr
}

那么这个指针的意义是什么?难道只是一个观星者吗?
答案:解除循环依赖问题

假设我们现在有两个对象A和B

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A{
public:
void setpb(B* b){
pb.reset(b);
}
private:
shared_ptr<B> pb;

}
class B{
public:
void setpb(A* a){
pb.reset(a);
}
private:
shared_ptr<A> pa;
}

在我们实例化A类和B类,并调用两个set方法注入A和B的成员指针后,A和B构成了循环依赖,这两个类会因为该依赖关系而都无法被自动销毁(永远都会因为对方的成员指针而导致计数器不为0),此时我们可以调用weak_ptr获取实例之后进行手动销毁
注意:通过weak_ptr的成员函数lock()获取的是其引用的shared_ptr所指向的对象,并不是副本或拷贝