我们从之前对于auto_ptr和unique_ptr介绍可以的知:
已经消失的智能指针——auto_ptr:https://blog.csdn.net/qq_46423166/article/details/113764347
C++智能指针——unique_ptr:https://blog.csdn.net/qq_46423166/article/details/113777696
- auto_ptr有很多问题,比如指针之间可以互相赋值,移动之后一个为空的问题。现在已经被弃用
- 然后unique_ptr不能直接使用复制构造函数,但是通过别的方法依然会出现两个指针指向同一个地址的错误,因此也有问题。
此时就产生了第三种智能指针:
shared_ptr
这种指针和unique_ptr的主要区别就是,允许多个指针指向同一个对象。
一些相同的用法就不解释了,这里主要解释一些与shaerd_ptr单独的用法:
1,首先介绍关于定义的make_shared函数:
这是最安全的分配和使用动态内存的方法,它动态分配一个对象并初始化,并且返回次对象的shared_ptr。
定义方法:
shared_ptr<int> a = make_shared<int>();
shared_ptr<int> b = make_shared<int>(42);
shared_ptr<string> c = make_shared<string>(10,'9');
2,shared_ptr的拷贝和赋值
这种指针比较允许多个指针指向同一个对象的原因就是有一个叫做引用计数的东西,即每个shared_ptr关联的一个计数器
shared_ptr<int> a = make_shared<int>();
auto b(a);
- 第二行运行结束后,a和b就指向了同一个对象,因此shared_ptr关联的计数器就会递增。
- 当a或者b被销毁后,这个关联的计数器就会递减。
此时我们可以用新函数use_count()函数来显示
如上图所示:
- 红色线表示刚初始化,因此计数器为1
- 绿色线表示a,b同时指向一个对象,因此计数器加一变为2
- 因为b是临时对象,所以当test函数之后,b就被销毁了,计数器递减,又变为1
此时又引出了新的函数:unique();
表示如果计数器为1,则返回true,否则返回false。
3,shared_ptr自动销毁所管理的对象和相关联的内存
当指向一个对象的最后一个shared_ptr被销毁时,他就会调用类的成员函数——析构函数来完成销毁工作;
析构函数会递减它指向的对象的引用计数。如果引用计数变为0,shared_ptr的析构函数就会销毁对象,并释放它占的内存。
对于一块内存,使用shared_ptr安全的原因就是:
shared_ptr类报这个只要有任何shared_ptr对象引用它,它就不会被释放掉
但是如果将shared_ptr存放在一个容器中,随后重排了容器,从而不需要某些元素。这种情况下要确保erase删除了那些不在需要的shared_ptr元素。
weak_ptr
这个是一个弱引用,不控制所指向对象生存期的智能指针,他指向一个shared_ptr管理的对象。
弱引用的意思就是:
- 将一个weak_ptr绑定到一个shared_ptr不会改变引用计数。
- 最后一个指向对象的shared_ptr被销毁,对象就会被释放。即使有weak_ptr指向对象,对象也还是会被释放。
定义:
auto a = make_shared<int>(10);
weak_ptr<int> b(a);
使用 cout << a.use_count() << endl;观察结果为1,表示引用计数并没有增加。
因为这里使用的是弱引用,所以如果使用weak_ptr的话,就需要提前判断指向的shared_ptr是否存在。
此时使用 b.lock()结果为true。
关于weak_ptr的一些函数:
- b.reset() 将b置为空
- b.use_count() 与b共享对象的shared_ptr的数量,若数量为0,则返回true,否则返会false。
- b.expired() 如果为true,则返回一个空的shared_ptr;否则返回一个指向b的对象的shared_ptr