5.3c++:shared_ptr的常用操作、计数、自定义删除器等(转载)

   shared_ptr 引用计数的增加和减少

共享式:引用计数,每一个 shared_ptr的拷贝都指向相同的内存(对象),只有最后一个指向该对象的shared_ptr指针不需要再指向该对象的时候,才会析构对象。

1.1引用计数的增加
每个shared_ptr都会记录有多少个其他的shared_ptr指向相同的对象
 
auto p6 = make_shared<int> (200);目前p6所指向的对象只有p6一个引用者
auto p7(p6);  智能指针定义的初始化,p7和p6指向了相同的对象,此对象目前有两个引用者
在如下情况下,所有指向这个对象的shared_ptr引用计数都会增加1:
 
a)像上边这样,我们用p6来初始化p7这个智能指针;
auto p7(p6); 
 
b)把智能指针当做实参往函数里传递。
    void myfunc(shared_ptr<int> ptmp)
    {
       return ;
    }  
    myfunc(p7);  实参传递的时候,会复制到ptmp,会增加引用计数,出来的时候会减少1
 
    void myfunc(shared_ptr<int> &ptmp)
    {
       return ;
    }    
    myfunc(p7);  实参传递的是引用的时候,这样就不会出现引用计数的增加。
 
c)作为函数的返回值
    
    shared_ptr<int>  myfunc(shared_ptr<int> &ptmp)
    {
       return ;
    }    
    auto p8 = myFunc(p7);
 
    这里有p8来接,引用计数加一,
    如果是:myFunc(p7); 引用计数就不会改变。
 1.2引用计数的减少
shared_ptr<int>  myfunc(shared_ptr<int> &ptmp)
    {
       return ;
    }       
auto p6 = make_shared<int> (200);
auto p7(p6);
auto p8 = 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,则它会自动释放自己所管理(指向)的对象。
 auto pp = make_shared<int> (100); //只有pp指向该对象
 auto pp2 = make_shared<int> (100);
 pp = pp2;
 给pp赋值会让pp指向pp2指向的对象,pp2对象引用计数变为2
 原来的pp所指向的对象的引用计数变为0,从而被释放

shared_ptr指针的常用操作、删除器


(1)
use_count():返回多少个智能指针指向某个对象,主要用于调试的目的。
  
 shared_ptr<int> myp(new int(100));
 int icount = 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 (new int(10));
   if(myunique.unique())
   {
        cout << "unique ok" <<endl;
   }
(3)
reset(): 恢复(复位、重置)的意思
(a): reset()不带参数的时候
 
若pi是唯一指向该对象的指针,那么释放pi所指向的对象,并将pi置空
     pi.reset();
     if(pi == nullptr)
     {
         cout << "pi被置空" <<endl;
     }
若pi不是唯一指向该对象的指针,那么不释放pi所指向的对象,但指向该对象的引用计数会减少1,同时将pi指空
    shared_ptr<int> pi(new int(100));
    shared_ptr<int> pi2(new int(100));
    pi = pi2;
    int iCount = 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(new int(100));
     pp.reset (new int (1000));//释放原内存,指向新内存。
     cout << *pp << endl;//1000
  若pp不是唯一指向该对象的指针,则不释放pp指向的对象,但
  指向该对象的引用计数会减少1,同时让pp指向新对象。
     shared_ptr<int> pp(new int(100));
     auto pp3(pp);  //pp3 和 pp 的引用计数都是2
     pp.reset(new int(200));
     cout << pp3.unique() << endl;//1
     cout << *pp << endl;//200
     cout << *pp3 << endl;//100
 
     //空指针也可以通过reset来重新初始化
     shared_ptr<int> p;
     p.reset (new int(11));//释放p所指向的对象,让p指向新对象
(4)
*解引用:获取p指向的对象。
 
     shared_ptr<int> sptr(new int(100));
     cout << *sptr << endl;  // 打印100
(5)
get ();
   返回p中保存的指针。小心使用,如果智能指针释放了所指向额对象
   那么这个返回的裸指针也就变得失效。
   存在的必要:考虑到有些函数(第三方函数)的参数需要是一个内置裸指针,而不是智能指针。
    shared_ptr<int> getp (new int(122));
    int *q = getp.get();
    *q = 45;
    cout << *getp <<endl;
    //delete q; 尽量不要这样写,会产生不可预料的错误。
(6)
swap();
交换两个智能指针所指向的对象。
 
    shared_ptr<int> swapp (new int(120));
    shared_ptr<int> swapp2 (new int(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 (new string ("hello world"));
    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 (new string ("hello world"));
 
    if(sharptr)
    {
        cout << "智能指针不是空的" << endl;
    }
    else{
 
        cout << "智能指针是空的" <<endl;
    }

指定删除器以及数组问题

指定删除器:

#include <iostream>
#include <vector>
#include <memory> // shared_ptr
using namespace std;
 
void myDelete (int *p)//自己的删除器,删除整型指针用的,当智能指针引用计数为0
//就会自动调用来删除对象。
{
    //写一些日志
    cout << "这里被调用了"<<endl;
    delete p;
}
 
int main()
{
一定时机帮我们删除所指向的对象,delete:将delete运算符作为默认的资源析构函数
    
我们可以指定自己的删除器取代系统提供的默认删除器
方法:一般只需要在参数中添加具体的删除函数名即可。
 
    shared_ptr<int> pdelete (new int (1234) ,myDelete) ;
    shared_ptr<int> pdelete2(pdelete);
 
    pdelete.reset();
    pdelete2.reset();
    cout << pdelete.use_count() <<endl;
    cout << pdelete2.use_count() <<endl;
 
有些情况默认删除器处理不了(用shared_ptr管理动态数组),需要我们 提供自己指定的删除器
   return 0;
}
#include <iostream>
#include <memory> // shared_ptr
using namespace std;
 
int main()
{
     删除器可以是lambda:表达式   
     shared_ptr<int> plambda(new int(123),[](int *p){
           delete p;
     });
 
有些情况默认删除器处理不了(用shared_ptr管理动态数组),需要我们  提供自己指定的删除器
     shared_ptr<int> pArray (new int[12] ,[](int*p){
                       delete []p;
                       });
 
     shared_ptr<A> pA(new A[12]); //异常因为系统释放pA是delete,pA应用delete []pA;
 
     shared_ptr<A> pA(new A[12],[](A *p){
                     delete[]p;
                     });
 
}
 default_delete
可用default_delete 来做删除器。default_delete 是标准库里的模板类
 
shared_ptr<A> pDefault (new A[12] ,default_delete<A[]>());
 
定义数组的时候,我们在尖括号里加[]
 
shared_ptr<A[]> pA_1(new A[10]);
shared_ptr<int[]> pA_2(new int[12]);
函数模板来封装shared_ptr 数组
#include <iostream>
#include <memory> // shared_ptr
using namespace std;
 
 
template <typename T>
shared_ptr<T> make_shared_array(size_t size)
{
    return shared_ptr<T> (new T[size],default_delete <T[]> ());
}
 
class A
{
public:
    A(){};
    ~A(){};
};
 
int main()
{
 
  自己定义函数封装shared_ptr数组
   shared_ptr<int> pintArray = make_shared_array<int>( 5 );
   shared_ptr<A> pAAay = make_shared_array <A> (9);
 
   return 0;
}
 指定删除器额外声明:
#include <iostream>
#include <memory> // shared_ptr
using namespace std;
 
 
   auto lambda1 = [](int *p)
   {
       //日志
       delete p;
   };
   auto lambda_2 = [](int *q)
   {
       //日志
       delete q;
   };
 
class A
{
public:
    A(){};
    ~A(){};
};
 
int main()
{
 
就算是shared_ptr指定了不同的删除器,只要他们指向的对象类型相同,那么这两个shared_ptr也属于同一个类型
 
 
   shared_ptr<int> diffdelete(new int(122) ,lambda1);
   shared_ptr<int> diffdelete2(new int(11),lambda_2);
   diffdelete2 = diffdelete;
 
diffdlete2会先调用lambda2把自己指向的对象释放,然后指向diffdelete指向的对象,diffdelete指向的对象引用计数为2
 
整个main执行完毕之后,还会调用lambda1来释放diffdelete和diffdelete2共同指向的对象。
 
   return 0;
}

类型相同,就代表可以放到元素类型为该对象类型的容器里
   vector<shared_ptr<int>> pvec{diffdelete,diffdelete2};

make_shared 是提倡的生成shared_ptr的方法,但是make_shared这种方法,让我们没有方法指定自己的删除器。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值