C++总结8——shared_ptr和weak_ptr智能指针
来源:互联网 发布:网络用语开屏 编辑:程序博客网 时间:2024/06/07 01:28
智能指针的提出:智能指针是存储指向动态分配对象指针的类,用于生存期控制。能够确保正确销毁动态分配的内存,防止内存泄露。
1.智能指针的分类:
不带引用计数的智能指针
auto_ptr unique_ptr scoped_ptr
带引用计数的智能指针
shared_ptr:强智能指针
weak_ptr:若智能指针
2.不带引用计数的智能指针是如何确保正确释放堆上内存的?
auto_ptr:
auto_ptr<A> ptr1(new A(10));auto_ptr<A> ptr2 = ptr1;
当这两行代码执行完后,ptr1已经不再指向A这个对象,并且ptr1=NULL,ptr1对A对象的所有权已经转移给了ptr2,也就不能通过ptr1调用该类的方法。
vector<auto_ptr<int>> vec;
不能将auto_ptr类型的指针作为STL容器的元素。因为容器避免不了直接拷贝构造和互相赋值。auto_ptr的这种特性会给STL容器的使用造成很大的麻烦。
unique_ptr:
unique_ptr<A> ptr1(new A(10));unique_ptr<A> ptr2 = ptr1;//errorunique_ptr<A> ptr3 = func();//ok
unique_ptr不支持拷贝构造函数和赋值运算符重载函数,不能隐式的将原指针置为NULL,但是可以通过返回值赋值。unique_ptr支持移动构造函数和移动赋值运算符重载函数,是通过move(C++11标准)函数实现的,用户明确知道对象的所有权已经发生转移,不能再使用原来的指针调用类的方法。这也是auto_ptr和unique_ptr最根本的区别。
scoped_ptr:
scoped_ptr不支持所有权的转移,只能通过该指针对对象进行操作,出作用域会自动析构。
3.带引用计数的智能指针
shared_ptr<A> pa(new A());shared_ptr<A> pb = pa;
当使用指针指向堆上的对象时,该对象的引用计数加1。拷贝构造或赋值时,不产生该对象的副本,只是更改对象的引用计数。如果别的智能指针也指向这个对象时,也是增加其引用计数。如果delete 指针时,先对引用计数减1,直到对象的引用计数减为0,才调用该对象的析构函数。
4.智能指针的交叉引用导致内存泄露
class A{public: shared_ptr<B> _pb;};class B{public: shared_ptr<A> _pa;};int main(){ shared_ptr<A> pa(new A()); shared_ptr<B> pb(new B()); pa->_pb = pb; pb->_pa = pa; return 0;}
pa指针指向堆上对象后,A的引用计数是1,B的引用计数是1。
pa->_pb = pb;此时,B的引用计数是2。
pb->_pa = pa;此时,A的引用计数是2。
出作用域后:
pb指针释放,B对象的引用计数减1,此时,B的引用计数是1,并不调用B的析构函数。
pa指针释放,A对象的引用计数减1,此时,A的引用计数是1,并不调用A的析构函数。
程序运行结束,A和B对象并未析构,造成内存泄露
为了避免内存泄露,必须打断这种循环等待的现象。智能指针提供了weak_ptr(弱智能指针)可以避免产生循环等待的现象。
weak_ptr,当用weak_ptr指向对象时,对象的引用计数并不加1,因为弱智能指针没有对对象的使用权,它只有监控权。
#include <iostream>#include <memory>using namespace std;class A{public: weak_ptr<B> _pb;};class B{public: shared_ptr<A> _pa;};int main(){ shared_ptr<A> pa(new A()); shared_ptr<B> pb(new B()); pa->_pb = pb; pb->_pa = pa; return 0;}
pa指针指向堆上对象后,A的引用计数是1,B的引用计数是1。
pa->_pb = pb;此时,B的引用计数是1。因为A的成员对象是weak_ptr。
pb->_pa = pa;此时,A的引用计数是2。
出作用域后:
pb指针释放,B对象的引用计数减1,此时,B的引用计数是0,调用B的析构函数,先析构自己(B被析构),再析构成员对象(A的引用计数减1,此时A的引用计数是1)
pa指针释放,A对象的引用计数减1,此时,A的引用计数是0,调用A的析构函数(A被析构)
为了避免智能指针循环引用造成的内存泄露情况,要遵守:创建对象的时候,一定要用强智能指针,其他地方只能用持有资源的弱智能指针。
智能指针本身是线程安全的。使用atomic_increment和atimic_decreament进行对多线程间的互斥,保证引用计数count++/count–是原子操作。
5.多线程访问共享的C++对象产生的线程安全的问题
#include <iostream>#include <memory>using namespace std;class C{public: C(){} ~C(){} void func(){cout<<"call func()"<<endl;}};void* threadProc(void *lparg){ shared_ptr<C> pc = (shared_ptr<C>)lparg; pc->func();//如果对象已经析构,则程序崩溃! return NULL;}int main(int argc, char* argv[]){ shared_ptr<C> c(new C()); pthread_t tid; pthread_create(&tid, NULL, threadProc, &c); return 0;}
多线程中可能访问共享的对象,如果对象已经析构,线程中访问它,程序会崩溃掉。解决多线程访问共享的C++对象产生的线程安全的问题,可以使用weak_ptr。将弱智能指针转给线程,再访问对象时,先将弱智能和提升为强智能指针,如果提升成功,则说明对象还存在,可以访问该对象的成员变量或方法。如果提升失败,则说明对象已经析构。
#include <iostream>#include <memory>using namespace std;class C{public: C(){} ~C(){} void func(){cout<<"call func()"<<endl;}};void* threadProc(void *lparg){ weak_ptr<C> pw = *(weak_ptr<C>*)lparg; shared_ptr<C> pc = pw.lock();//类型提升 if(pc != NULL)//类型提升成功,对象未析构 { pc->func(); } return NULL;}int main(int argc, char* argv[]){ shared_ptr<C> c(new C()); pthread_t tid; weak_ptr<C> pw(c); pthread_create(&tid, NULL, threadProc, &pw); return 0;}
创建对象的时候一定要用强智能指针,其他地方只能用持有资源的弱智能指针!!!
- C++总结8——shared_ptr和weak_ptr智能指针
- 智能指针---shared_ptr和weak_ptr
- C++:智能指针-TR1的shared_ptr和weak_ptr使用介绍
- C++:智能指针-TR1的shared_ptr和weak_ptr使用介绍
- 智能指针shared_ptr、weak_ptr、unique_ptr总结
- 【C++】智能指针auto_ptr/unique_ptr/shared_ptr/weak_ptr!!!
- 智能指针--shared_ptr&&weak_ptr
- c++ 智能指针- shared_ptr和weak_ptr
- boost智能指针之shared_ptr和weak_ptr
- C++智能指针 shared_ptr,unique_ptr和weak_ptr
- 智能指针auto_ptr、scoped_ptr、shared_ptr和weak_ptr
- Boost智能指针——weak_ptr vs shared_ptr
- Boost智能指针——scoped_ptr、shared_ptr、weak_ptr、intrusive_ptr
- 智能指针——auto_ptr、shared_ptr、weak_ptr、scoped_ptr
- C++中的智能指针——auto_ptr, unique_ptr, shared_ptr和weak_ptr
- Boost智能指针shared_ptr、weak_ptr
- 智能指针--scoped_ptr shared_ptr weak_ptr
- 智能指针scoped_ptr,shared_ptr,weak_ptr和auto_ptr的使用
- vue实现购物车动画功能
- Java多线程系列--“JUC集合”01之 框架
- Numerically Speaking hdu 1314 大数模拟
- monkeyruuner介绍与应用
- codeforces 584C Marina and Vasya
- C++总结8——shared_ptr和weak_ptr智能指针
- serialVersionUID 的使用
- 安装AndroidStudio2.3.3
- 知乎校招面经,拿到offer
- Android 6.0 运行时权限处理完全解析
- IntelliJ IDE中无法运行java程序
- 判断链表是否带环?若带环求环的长度?若带环求环的入口点?并计算以上每个问题的时间复杂度?
- 基础总结
- mysql 多表查询