共享式:引用计数,每一个shared_ptr的拷贝都指向相同的内存(对象),只有最后一个指向该对象的shared_ptr指针不需要再指向该对象的时候,才会析构对象。
1.1引用计数的增加
每个shared_ptr都会记录有多少个其他的shared_ptr指向相同的对象
autop6=make_shared<int>(200);目前p6所指向的对象只有p6一个引用者
autop7(p6);智能指针定义的初始化,p7和p6指向了相同的对象,此对象目前有两个引用者
在如下情况下,所有指向这个对象的shared_ptr引用计数都会增加1:
a)像上边这样,我们用p6来初始化p7这个智能指针;
autop7(p6);
b)把智能指针当做实参往函数里传递。
voidmyfunc(shared_ptr<int>ptmp)
{
return;
}
myfunc(p7);实参传递的时候,会复制到ptmp,会增加引用计数,出来的时候会减少1
voidmyfunc(shared_ptr<int>&ptmp)
{
return;
}
myfunc(p7);实参传递的是引用的时候,这样就不会出现引用计数的增加。
c)作为函数的返回值
shared_ptr<int>myfunc(shared_ptr<int>&ptmp)
{
return;
}
autop8=myFunc(p7);
这里有p8来接,引用计数加一,
如果是:myFunc(p7);引用计数就不会改变。
1.2引用计数的减少
shared_ptr<int>myfunc(shared_ptr<int>&ptmp)
{
return;
}
autop6=make_shared<int>(200);
autop7(p6);
autop8=myFunc(p7);现在引用计数是3
a)给shared_ptr赋予新值,让该shared_ptr指向一个新对象
p8=make_shared<int>(100);p8指向新对象,计数为1,p7,p6计数恢复为2
p7=make_shared<int>(900);p7指向新对象,计数为1,p6指向的对象恢复为1
p6=make_shared<int>(900);p6指向新对象,计数为1,p6指向的原内存被释放
b)局部的shared_ptr离开了作用域
就是上边那个传参的情况,进入之后加1,出来之后会被析构,计数减1;
c)当一个shared_ptr引用计数从1变成0,则它会自动释放自己所管理(指向)的对象。
autopp=make_shared<int>(100);//只有pp指向该对象
autopp2=make_shared<int>(100);
pp=pp2;
给pp赋值会让pp指向pp2指向的对象,pp2对象引用计数变为2
原来的pp所指向的对象的引用计数变为0,从而被释放
shared_ptr指针的常用操作、删除器
(1)
use_count():返回多少个智能指针指向某个对象,主要用于调试的目的。
shared_ptr<int>myp(newint(100));
inticount=myp.use_count();//1
cout<<icount<<endl;
shared_ptr<int>myp2(myp);
icount=myp.use_count();//2
cout<<icount<<endl;
myp和myp2都指向相同的内存,所以数量都相同。
(2)
unique():是否该智能指针独占某个指向的对象。
也就是若只有一个智能指针指向某个对象,则unique()返回true否则false
shared_ptr<int>myunique(newint(10));
if(myunique.unique())
{
cout<<"uniqueok"<<endl;
}
(3)
reset():恢复(复位、重置)的意思
(a):reset()不带参数的时候
若pi是唯一指向该对象的指针,那么释放pi所指向的对象,并将pi置空
pi.reset();
if(pi==nullptr)
{
cout<<"pi被置空"<<endl;
}
若pi不是唯一指向该对象的指针,那么不释放pi所指向的对象,但指向该对象的引用计数会减少1,同时将pi指空
shared_ptr<int>pi(newint(100));
shared_ptr<int>pi2(newint(100));
pi=pi2;
intiCount=pi2.use_count();
cout<<iCount<<endl;//2
iCount=pi.use_count();
cout<<iCount<<endl;//2
pi.reset();
iCount=pi.use_count();//0
cout<<iCount<<endl;
iCount=pi2.use_count();//1
cout<<iCount<<endl;
(b)reset()带参数(一般是一个new出来的指针)时,
若pp是唯一指向该对象的指针,则释放pi指向的对象,让pi指向新对象
shared_ptr<int>pp(newint(100));
pp.reset(newint(1000));//释放原内存,指向新内存。
cout<<*pp<<endl;//1000
若pp不是唯一指向该对象的指针,则不释放pp指向的对象,但
指向该对象的引用计数会减少1,同时让pp指向新对象。
shared_ptr<int>pp(newint(100));
autopp3(pp);//pp3和pp的引用计数都是2
pp.reset(newint(200));
cout<<pp3.unique()<<endl;//1
cout<<*pp<<endl;//200
cout<<*pp3<<endl;//100
//空指针也可以通过reset来重新初始化
shared_ptr<int>p;
p.reset(newint(11));//释放p所指向的对象,让p指向新对象
(4)
*解引用:获取p指向的对象。
shared_ptr<int>sptr(newint(100));
cout<<*sptr<<endl;//打印100
(5)
get();
返回p中保存的指针。小心使用,如果智能指针释放了所指向额对象
那么这个返回的裸指针也就变得失效。
存在的必要:考虑到有些函数(第三方函数)的参数需要是一个内置裸指针,而不是智能指针。
shared_ptr<int>getp(newint(122));
int*q=getp.get();
*q=45;
cout<<*getp<<endl;
//deleteq;尽量不要这样写,会产生不可预料的错误。
(6)
swap();
交换两个智能指针所指向的对象。
shared_ptr<int>swapp(newint(120));
shared_ptr<int>swapp2(newint(122));
swap(swapp,swapp2);
cout<<*swapp<<endl;//122
cout<<*swapp2<<endl;//120
swapp.swap(swapp2);
cout<<*swapp<<endl;//120
cout<<*swapp2<<endl;//122
(7)=nullptr
a)将所指向的对象,引用计数减1,若引用计数变为0,则释放智能指针所指向的对象。
b)将智能指针置空。
shared_ptr<string>sharptr(newstring("helloworld"));
shared_ptr<string>sharptr2(sharptr);
cout<<sharptr.use_count()<<endl;//2
cout<<sharptr2.use_count()<<endl;//2
sharptr=nullptr;
cout<<sharptr.use_count()<<endl;//0
cout<<sharptr2.use_count()<<endl;//1
(8)智能指针名字作为判断条件。
可以判断是否为空
shared_ptr<string>sharptr(newstring("helloworld"));
if(sharptr)
{
cout<<"智能指针不是空的"<<endl;
}
else{
cout<<"智能指针是空的"<<endl;
}
指定删除器以及数组问题
指定删除器:
#include<iostream>
#include<vector>
#include<memory>//shared_ptr
usingnamespacestd;
voidmyDelete(int*p)//自己的删除器,删除整型指针用的,当智能指针引用计数为0
//就会自动调用来删除对象。
{
//写一些日志
cout<<"这里被调用了"<<endl;
deletep;
}
intmain()
{
一定时机帮我们删除所指向的对象,delete:将delete运算符作为默认的资源析构函数
我们可以指定自己的删除器取代系统提供的默认删除器
方法:一般只需要在参数中添加具体的删除函数名即可。
shared_ptr<int>pdelete(newint(1234),myDelete);
shared_ptr<int>pdelete2(pdelete);
pdelete.reset();
pdelete2.reset();
cout<<pdelete.use_count()<<endl;
cout<<pdelete2.use_count()<<endl;
有些情况默认删除器处理不了(用shared_ptr管理动态数组),需要我们提供自己指定的删除器
return0;
}
#include<iostream>
#include<memory>//shared_ptr
usingnamespacestd;
intmain()
{
删除器可以是lambda:表达式
shared_ptr<int>plambda(newint(123),[](int*p){
deletep;
});
有些情况默认删除器处理不了(用shared_ptr管理动态数组),需要我们提供自己指定的删除器
shared_ptr<int>pArray(newint[12],[](int*p){
delete[]p;
});
shared_ptr<A>pA(newA[12]);//异常因为系统释放pA是delete,pA应用delete[]pA;
shared_ptr<A>pA(newA[12],[](A*p){
delete[]p;
});
}
default_delete
可用default_delete来做删除器。default_delete是标准库里的模板类
shared_ptr<A>pDefault(newA[12],default_delete<A[]>());
定义数组的时候,我们在尖括号里加[]
shared_ptr<A[]>pA_1(newA[10]);
shared_ptr<int[]>pA_2(newint[12]);
函数模板来封装shared_ptr数组
#include<iostream>
#include<memory>//shared_ptr
usingnamespacestd;
template<typenameT>
shared_ptr<T>make_shared_array(size_tsize)
{
returnshared_ptr<T>(newT[size],default_delete<T[]>());
}
classA
{
public:
A(){};
~A(){};
};
intmain()
{
自己定义函数封装shared_ptr数组
shared_ptr<int>pintArray=make_shared_array<int>(5);
shared_ptr<A>pAAay=make_shared_array<A>(9);
return0;
}
指定删除器额外声明:
#include<iostream>
#include<memory>//shared_ptr
usingnamespacestd;
autolambda1=[](int*p)
{
deletep;
};
autolambda_2=[](int*q)
{
deleteq;
};
classA
{
public:
A(){};
~A(){};
};
intmain()
{
就算是shared_ptr指定了不同的删除器,只要他们指向的对象类型相同,那么这两个shared_ptr也属于同一个类型
shared_ptr<int>diffdelete(newint(122),lambda1);
shared_ptr<int>diffdelete2(newint(11),lambda_2);
diffdelete2=diffdelete;
diffdlete2会先调用lambda2把自己指向的对象释放,然后指向diffdelete指向的对象,diffdelete指向的对象引用计数为2
整个main执行完毕之后,还会调用lambda1来释放diffdelete和diffdelete2共同指向的对象。
return0;
}
类型相同,就代表可以放到元素类型为该对象类型的容器里
vector<shared_ptr<int>>pvec{diffdelete,diffdelete2};
make_shared是提倡的生成shared_ptr的方法,但是make_shared这种方法,让我们没有方法指定自己的删除器
来源:oschina
链接:https://my.oschina.net/u/920274/blog/4341421