智能指针学习(C++)
智能指针就是帮我们C++程序员管理动态分配的内存(这里主要就是指new、malloc出来的堆内存),它会帮助我们自动释放内存,从而 避免内存泄漏。
头文件:
#include< memory >
智能指针常用的几个接口:
四种智能指针主要用法:
1.auto_ptr
采⽤所有权模式。(C++98 的⽅案,C++11 已抛弃)
使用:
auto_ptr<string>ap(new string("i am auto_ptr"));
auto_ptr<string>ap1 = ap;
cout << (*ap1 ).c_str()<< endl;//输出"i am auto_ptr"
cout << (*ap).c_str() << endl;//不会报错,但运行会崩溃
如上例子所示,该类型指针在进行新的赋值后,原有的指针就失去所有权,,再调用原指针,就会导致系统内存发生崩溃
2.unique_ptr(独占指针)
unique_ptr 实现独占式拥有或严格拥有概念,保证同⼀时间内只有⼀个智能指针可以指向该对象。它对于避免资源泄露特别有⽤。相比于auto_ptr,它仍然是所有权模式,但其不能指向有效数据
unique_ptr<string>autop(new string("iam unique_ptr"));
unique_ptr<string>autop1;
//1.
autop1 = autop;//会报错
unique_ptr<string>autop2 =(autop);//会报错,禁止左值构造、赋值
autop1 = move(autop);//通过吗,move将左值变为右值,就可以赋值了
//2.
unique_ptr<char[]>arry(new char[10]);
auto_ptr<char[]>autoarry(new char[10]); //auto_ptr不支持对象数组的操作
//3.
vector<unique_ptr<string>>up;
特点 :
1.无法进行左值复制赋值操作,但允许临时右值赋值构造和赋值
2.支持对象数组的内存管理
3.stl容器中使用智能指针,也不允许直接赋值
3.shared_ptr(共享指针)
shared_ptr 实现共享式拥有概念,多个智能指针可以指向相同对象,该对象和其相关资源会在“最后⼀个引⽤被销毁”时候释放。,在使⽤引⽤计数的机制上提供了可以共享所有权的智能指针。当计数为0时,其会自动销毁所管理的对象。
主要用法:
//构造:
//构造函数
shared_ptr 指针名 <T>(args);//args 为new 动态分配初始化的对象
shared_ptr 指针名 <T>(P);//P为shared_ptr类型的指针,或者内置指针(普通指针)
shared_ptr 指针名 <T>(P,d);//P为shared_ptr类型的指针,或者内置指针(普通指针),d指定一个删除器
// 空的shared_ptr;利用reset托管普通类型指针
shared_ptr<T> sp1;T *p1=new T();sp1.reset(p1);
//make_shared函数
shared_ptr<T>=make_shered<T>();//make_shared(类型);
//赋值
P1=P2;//P1,P2都是共享智能指针
//重置
shared_ptr< int > p(new int(10));
p.reset();p所管理对象引用计数为1,
p.reset(p1);p所管理对象引用计数为1,p接管对p1指针的管控,
p.reset(p1,d);p所管理对象引用计数为1,p管控的对象计数减1并使用d作为删除器(代替delete)
可以通过成员函数 use_count()查看资源的所有者个数,下面例子,示意了函数、赋值调用
shared_ptr<string>sharedp(new string("i am shared_ptr"));
cout << sharedp.use_count() << endl;//返回与sharedp共享指针的数量
shared_ptr<string>sharedp1 = sharedp;//注意智能指针赋值左右两边都必须要是shared_ptr
cout<<sharedp.use_count()<<endl;//返回与sharedp共享指针的数量
shared_ptr<string>sharedp2(sharedp);
cout << sharedp.use_count() << endl;//返回与sharedp共享指针的数量
pra_sharedptr(sharedp);
cout << sharedp.use_count() << endl;//返回与sharedp共享指针的数量
void pra_sharedptr(shared_ptr<string>sharedp)
{
cout << sharedp.use_count()<<endl;
}
结果:
i am auto_ptr
1
2
3
4
3
该指针使用时要注意以下问题:
- 尽量不要混合使用普通指针和智能指针
void pro(shared_ptr<int> ptr)
{
//离开作用域之后就释放了。
}
int* p= new int(125);
pro(shared_ptr<int>(p));
int c = *p;
cout << c;
结果:
-572662307 //p说明已经被释放了
- 使用get获取的指针不能再给另外一个智能指针赋值(又或者说,get获取的指针,不能用delete,只能由get的那个智能指针来销毁t);
例子:
shared_ptr<int> a = make_shared<int>(3);
int* pp = a.get();
{
shared_ptr<int> b(pp);
}//作用域结束后,b释放pp,而此时a指向的pp就已经释放了,此处系统运行直接报错
cout << *pp << endl;
- 互相引用导致无法释放资源,导致无法释放问题
例子:比如A类使用了B类的智能指针,B类使用了A类的智能指针;
class B;
class A
{
public:
A()
{
cout << "A make" << endl;
}
~A()
{
cout << "A delete" << endl;
}
void getb(shared_ptr<B> b)
{
this->b =b ;
}
private:
shared_ptr<B> b;
};
class B
{
public:
B()
{
cout << "B make" << endl;
}
~B()
{
cout << "B delete" << endl;
}
void geta(shared_ptr<A> a)
{
this->a = a;
}
private:
shared_ptr<A> a;
};
{
shared_ptr<A>sharedpA(new A());//sharedpB计数1
shared_ptr<B>sharedpB(new B());//sharedpB计数1
sharedpA->getb(sharedpB);//sharedpB计数2
sharedpB->geta(sharedpA);//sharedpA计数2
}
结果:
A make
B make
A\B都没有析构
分析:
A、B类互相有对方的管理对象,此时计数为2(代码块定义指针+1,互相引用指针计数+1),导致代码块运行结束后,sharedpB、sharedpA(即代码块定义的智能指针会销毁,此时计数减一,但此时计数仍然还有1,sharedpB、sharedpA所指向的对象没有被销毁)
4.weak_ptr 弱指针
weak_ptr 是⼀种不控制对象⽣命周期的智能指针,它指向⼀个 shared_ptr 管理的对象。进⾏该对象的内存管理的是那个强引⽤的 shared_ptr。
weak_ptr 只是提供了对管理对象的⼀个访问⼿段。weak_ptr 设计的⽬的是为配合 shared_ptr ⽽引⼊的⼀种智能指针来协助 shared_ptr ⼯作,它只可以从⼀个 shared_ptr 或另⼀个 weak_ptr 对象构造,它的构造和析构不会引起引⽤记数的增加或减少。
主要特点:
1.可以通过调⽤ lock 函数来获得shared_ptr。
2.弱指针也可以获得引用计数;
weak_ptr.use_count();
3.构造只能使用shared_ptr 或另⼀个 weak_ptr 对象来构造;
weak_ptr<int>wp;
wp=p1//p1只能为共享指针或者弱指针
weak_ptr<int>wp(p1);//p1只能为共享指针或者弱指针
wp.reset();//置空
wp.use_count();//与wp共享对象的shared_ptr的数量
wp.expired();//use_count==0,返回true,否则返回false(判断是否为空)
wp.lock()//如果弱指针为空(expired()返回值为true),返回一个空shared_ptr,否则返回一个指向(wp指向对象)的share_ptr;
使用方法:定义对象时,用强智能指针shared_ptr,在其它地方引用对象时,使用弱智能指针weak_ptr。
使用例子:(基于上个例子加入弱指针)
class B;
class A
{
public:
A()
{
cout << "A make" << endl;
}
~A()
{
cout << "A delete" << endl;
}
void getb(shared_ptr<B> b)
{
this->b =b ;
auto sb= this->b.lock();
cout <<"lock:"<< b.use_count() << endl;
sb= NULL;//将智能共享指针置空,此时计数归1
cout << "置空:"<<b.use_count() << endl;
}
private:
weak_ptr<B> b;
};
class B
{
public:
B()
{
cout << "B make" << endl;
}
~B()
{
cout << "B delete" << endl;
}
void geta(shared_ptr<A> a)
{
this->a = a;
}
private:
weak_ptr<A> a;
};
{
shared_ptr<A>sharedpA(new A());
shared_ptr<B>sharedpB(new B());
sharedpA->getb(sharedpB);
sharedpB->geta(sharedpA);
}
结果
A make
B make
lock:3
置空:2
B delete
A delete
智能指针使用注意补充:
1.不能使用相同内置指针来初始化多个智能指针。
2.get()获取的指针不能delete、初始化或者reset另外一个智能指针,管控这个指针的智能指针一旦计数为0,就会销毁该对象
3.当使用智能指针管理的对象资源不是用new来分配发内存,需要传递一个删除器