C++ 智能指针

 智能指针  

    是一个具体的类,生成智能指针对象时,在栈上,根据栈上对象出作用域自动析构的特点,达到对资源的释放 。

智能指针的浅拷贝问题 :

   不带引用计数 

  1. c++库 : auto_ptr(c++11 废弃)
  2. c11 新标准
  • scopet_ptr
  • unique_ptr

 

auto_ptr:

auto_ptr<int> ptr1 (new int);
auto_ptr<int> ptr2(ptr1);

 

auto_ptr 处理浅拷贝逻辑  源码上调用了 ptr1.release() 将ptr1 指向的空间 交给ptr2,将ptr1置为nullptr。

也就是说 将内存的控制权交给最后一个auto_ptr指针,那么在释放ptr1 会出错,这种情况对于不了解实现的用户是危险的

因此不推荐使用auto_ptr,因此在容器vector 或者其他容器中不能使用auto_ptr,只能在情况特别简单的情况下

 

scopet_ptr  的做法:

scopet_ptr(const scopet_ptr<T>&) = delete;
scopet_ptr<T> & operator= (const scopet_ptr<T> &) = delete;

直接将拷贝构造函数,赋值构造函数删除,无法进行赋值操作

 

推荐使用unique_ptr 做法:

unique_ptr(const unique_ptr<T>&) = delete;
unique_ptr<T> & operator= (const unique_ptr<T> &) = delete;
提供

unique_ptr(unique_ptr<T> && src)
unique_ptr<T> & operator = (unique_ptr<T> &&src)

那么我们在使用的时候 可以这样

unique_ptr<int> p1 (new int);
unique_ptr<int> p2(std::move(p1))

unique_ptr 提供了右值拷贝构造和赋值函数,那么我们使用c++11的std::move 获取右值,用户很清楚自己的操作,不会向auto_ptr一样。

 

带引用计数的智能指针:

shared_ptr  和 weak_ptr  (多个智能指针可以管理一个资源)

对每一个对象资源匹配一个引用计数,当出作用域的时候,当引用计数不为0 的时候,不析构。

实现shared_ptr

#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<unistd.h>
#include<atomic>
using namespace std;

template<typename T>
class RefCnt {

  public:
    RefCnt(T * ptr = nullptr):mptr(ptr) {
      if(mptr != nullptr ) {
        mcount = 1;
      }
    }
    void addMcount() {mcount++;}
    int delMcount() { return --mcount;}
  private:

    atomic_int mcount;
    T * mptr;
};


template<typename T>
class Myshared_ptr{

  public:
    Myshared_ptr(T * ptr =nullptr ) :mptr(ptr) {

      if(mptr != nullptr) {
        mRefCnt = new RefCnt<T>(mptr);
      }
    }
    ~Myshared_ptr() {

      if(0 == mRefCnt->delMcount()) {
        delete mptr;
        mptr == nullptr;
      }
    }
    T & operator *() {return *mptr;}
    T & operator ->() {return mptr;}
    Myshared_ptr (const Myshared_ptr<T> & src):mptr(src.mptr),mRefCnt(src.mRefCnt) {
      if(mptr != nullptr) {
        mRefCnt->addMcount();
      }
    }
    Myshared_ptr<T> & operator= (const Myshared_ptr<T> &src) {

      if(this == &src) {
        return *this;
      }

      if(0 == mRefCnt->delMcount()){
        delete mptr;
      }
      
      mptr = src.mptr;
      mRefCnt = src.mRefCnt;
      return *this;
    }
  private:
    RefCnt<T> * mRefCnt;
    T * mptr;

};
int main()
{
  Myshared_ptr<int> p(new int);
  Myshared_ptr<int> p2(new int);
  
  p2 = p;


    cout<<endl;
    return 0;
}

那么当多个指针管理同一个资源的时候,只是对引用计数的更改,当引用计数为0 的时候,析构资源。

 

shared_ptr 的交叉引用问题

shared_ptr(强智能指针) weak_ptr(若智能指针)可以理解为:强智能指针管理内存,弱智能指针观察强智能指针

#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<unistd.h>
#include<memory>
using namespace std;

class B;

class A {

  public:
    A(){ cout<<"A()"<<endl; }
    ~A(){ cout<<"~A()"<<endl; }
    shared_ptr<B> _ptrb;
};

class B {

  public:
    B() {cout<<"B()"<<endl;}
    ~B() {cout<<"~B()"<<endl;}
    shared_ptr<A> _ptra;
};

int main()
{
  shared_ptr<A> ptra(new A);
  shared_ptr<B> ptrb(new B);
  ptra->_ptrb = ptrb;
  ptrb->_ptra = ptra;
    cout<<endl;
    return 0;
}

这样的操作会让引用计数为2  无法释放,因此需要使用wead_ptr ,不会对引用计数更改,结论:定义对象的时候用强智能指针,对象引用的时候用弱指针指针

操作功能描述
weak_ptr<T> w 空weak_ptr,可以指向类型为T*的对象。
weak_ptr<T> w(sp) 与shared_sp sp指向相同对象的weak_ptr。T必须能转换为sp所指的类型。
w = p p可以是一个shared_ptr或一个weak_ptr。赋值后w指向p所指的对象。
w.reset() 将w置为空
w.use_count() 与w共享对象的shared_ptr的数量
w.expired() 若w.use_count()为0,返回true,否则返回false
w.lock() 如果expired()为true,返回一个空shared_ptr;否则返回一个指向w所指对象的shared_ptr。

特点 weak_ptr 没有* 和-> 运算符重载,需要使用w.lock() 挺升能力。

在多线程中 提升完判断 是否为空,来判断资源是否还在。

posted @ 2020-08-31 10:44  睡觉lc  阅读(212)  评论(0)    收藏  举报