一、智能指针的作用:
在C++中,动态内存的管理是用一对运算符完成的:new和delete,new:在动态内存中为对象分配一块空间并返回一个指向该对象的指针,delete:指向一个动态独享的指针,销毁对象,并释放与之关联的内存。
动态内存管理经常会出现三种问题:
1、申请之后忘记释放内存,会造成内存泄漏;
2、另一种是尚有指针引用内存的情况下就释放了它,就会产生引用非法内存的指针。
3、还有一种是内存的二次释放,即对同一个指针进行两次 free() 操作,可能导致程序崩溃
智能指针的作用就是解决上述三种可能出现的问题,指针指针的使用效率不会比一般的指针高,但是它胜在更安全、更稳定
二、智能指针的本质
智能指针的实质是一个类对象,它是利用模板类对一般的指针进行封装,在类内的构造函数实现对指针的初始化,并在析构函数里编写delete语句删除指针指向的内存空间。这样在程序过期的时候,对象会被删除,内存会被释放,实现指针的安全使用。
三、智能指针的类型和使用
智能指针是在C++11版本之后提供,包含在头文件#include<memory>中,智能指针有四种类型,分别是shared_ptr、unique_ptr、auto_ptr、weak_ptr,这里只介绍前两种
每种指针都有不同的使用范围,unique_ptr指针优于其它两种类型,除非对象需要共享时用shared_ptr。
如果你没有打算在多个线程之间来共享资源的话,那么就请使用unique_ptr。
1、shared_ptr
shared_ptr可以将多个指针指向相同的对象(共享)。shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,对象的引用计数
加1,每析构一次,对象的引用计数减1,减为0时,自动删除所指向的堆内存。
shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁。
shared_ptr的初始化
智能指针是个模板类,可以指定类型,传入指针通过构造函数初始化。也可以使用make_shared函数初始化。不能将指针直接赋值给一个智能指针,一
个是类,一个是指针。例如std::shared_ptr<int> p4 = new int(1);的写法是错误的
shared_ptr的拷贝和赋值
拷贝使得对象的引用计数增加1,赋值使得原对象引用计数减1,当计数为0时,自动释放内存。后来指向的对象引用计数加1,指向后来的对象。
shared_ptr传参的过程就是内存的拷贝,使得对象的引用计数增加1
#include <iostream> #include <memory> using namespace std; shared_ptr<int> func(shared_ptr<int> ps) { (*ps)++; cout<<"ps.use_count()="<<ps.use_count()<<endl; return ps; } int main() { int n=100; //赋值 shared_ptr<int>p=make_shared<int>(n); //拷贝 shared_ptr<int>q (p); cout<<"q.use_count()="<<q.use_count()<<endl; cout<<"p.use_count()="<<p.use_count()<<endl; //传参 p=func(p); cout<<"p=.use_count()"<<p.use_count()<<endl; cout<<*p<<endl; }
get函数获取原始指针
我们前面说过,shared_ptr的本质是一个模板类,这里通过get()函数可以获取它的原始指针
//创建共享指针同时赋值 ClassA是一个类 shared_ptr<ClassA> b = make_shared<ClassA>(100); //b是一个类,c是类指针 ClassA* c=b.get()
注意不要用一个原始指针初始化多个shared_ptr,否则会造成二次释放同一内存
2、unique_ptr
unique_ptr"唯一"拥有其所指对象,同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义来实现)
unique_ptr指针本身的生命周期:从unique_ptr指针创建时开始,直到离开作用域。离开作用域时,若其指向对象,则将其所指对象销毁(默认使用delete操作
符,用户可指定其他操作)。
unique_ptr指针与其所指对象的关系:在智能指针生命周期内,可以改变智能指针所指对象,如创建智能指针时通过构造函数指定、
通过reset方法重新指定、通过release方法释放所有权、通过移动语义转移所有权。
#include <iostream> #include <memory> int main() { { int a = 10; //动态绑定对象 std::unique_ptr<int> p (new int(a)); std::cout<<*p<<std::endl; //move转移所有权,转移之后指针p就变得无效了 std::unique_ptr<int> q=std::move(p); std::cout<<*q<<std::endl; //release释放所有权,释放之后指针q变的无效 q.release(); } }