天天看點

C++通用引用計數類/句柄類/指針類【智能指針(share_ptr)、右值引用】————附帶詳細代碼

文章目錄

  • ​​0 背景​​
  • ​​1 講解​​
  • ​​1.1 淺層拷貝句柄類​​
  • ​​1.2 淺、深層結合句柄類​​
  • ​​2 完整代碼示例​​

0 背景

在C++2.0中其實很多地方都用到了這種思想,如智能指針(share_ptr)、右值引用等。它實際上就是一個模版指針類,封裝了指向類的指針,當進行指派操作時,是拷貝一個新對象指派或者是指向同一個對象。在指向同一個對象時,為了防止對象被還有指向該對象的指針就被删除,設定引用計數,當指向的對象的指針需要修改該對象,而其他指針不需要使用到修改的對象時,可以拷貝一個新的對象,讓修改的指針指向。

這個類的好處在于可以避免大量不必要的記憶體管理和資料複制,提高了程式運作效率。

1 講解

1.1 淺層拷貝句柄類

兩個成員變量,指向對象的指針,引用計數的指針

template <typename T>
class ReferenceHandle{
private:
    T* m_p;
    std::size_t* m_refptr;
};      

構造函數:

//對象指針指向空指針,引用計數設定為1
    ReferenceHandle():m_p(nullptr),m_refptr(new std::size_t(1)){}
    //對象指針指向對象,引用計數設定為1
   ReferenceHandle(T* t):m_p(t),m_refptr(new std::size_t(1)){}      

拷貝構造函數:

//對象指針指向同一個對象,引用計數加1
    ReferenceHandle(const ReferenceHandle& h):m_p(nullptr),m_refptr(h.refptr){
        ++*m_refptr;
    }      

指派構造函數:

//為了防止自我指派時,
//還沒有指派就提前把對象删除了,這裡采取了先對對象引用計數+1
    ReferenceHandle&operator=(const ReferenceHandle& h){
        ++*m_refptr;
        if(--*m_refptr==0){
            delete m_refptr;
            delete m_p;
        }
        m_refptr = h.m_refptr;
        m_p = h.m_p;
        return *this;
    }      

析構函數:

//如果引用計數為0,則删除指向的對象和引用計數對象
    ~ReferenceHandle(){
        if(--*m_refptr==0){
            delete m_p;
            delete m_refptr;
        }
    }      

bool運算符函數:

//如果指針與實際對象關聯,則會傳回true,否則傳回false
    operator bool() const{ return  m_p;}      

operator*和operator->操作賦函數:

//用于通路指針指向的對象
    T&operator*()const {
        if(m_p) return *m_p;
        throw std::runtime_error("unbound Hanlde");
    }
    T*operator->()const {
        if(m_p) return m_p;
        throw std::runtime_error("unbound Hanlde");
    }      

1.2 淺、深層結合句柄類

成員對象:指向對象的指針、引用計數指針

template <typename T>
class Ptr{
private:
    T* m_p;
    std::size_t* m_refptr;
};      

拷貝構造函數:

ReferenceHandle():m_p(nullptr),m_refptr(new std::size_t(1)){}
    ReferenceHandle(T* t):m_p(t),m_refptr(new std::size_t(1)){}
    ReferenceHandle(const ReferenceHandle& h):m_p(nullptr),m_refptr(h.refptr){
        ++*m_refptr;
    }      

指派構造函數:

ReferenceHandle&operator=(const ReferenceHandle& h){
        ++*m_refptr;
        if(--*m_refptr==0){
            delete m_refptr;
            delete m_p;
        }
        m_refptr = h.m_refptr;
        m_p = h.m_p;
        return *this;
    }      

析構函數:

~ReferenceHandle(){
        if(--*m_refptr==0){
            delete m_p;
            delete m_refptr;
        }
    }      

操作符函數:

operator bool() const{ return  m_p;}
    T&operator*()const {
        if(m_p) return *m_p;
        throw std::runtime_error("unbound Hanlde");
    }
    T*operator->()const {
        if(m_p) return m_p;
        throw std::runtime_error("unbound Hanlde");
    }      

複制拷貝成員函數:

當指向的類是自己建立的類時,使用此函數:

//當存在會改變引用值的情況時,配置設定新對象
    void makeUnique(){
        if(*m_refptr != 1){
            --*m_refptr;
            m_refptr = new size_t(1);
            //成員函數版本
            m_p = m_p?m_p->clone():0;
            //全局函數版本
//            m_p = m_p?clone(m_p):0;
        }
    }      

複制拷貝非成員函數:

//非成員函數版本
//特化一個模版來處理成員函數中沒有clone()的情況(即沒有T::clone())
template <class T>T* clone(const T* tp){
    return tp->clone();
}

template <>
std::vector<char>* clone(const std::vector<char>* vp){
    return new std::vector<char>(*vp);
}

    void makeUnique(){
        if(*m_refptr != 1){
            --*m_refptr;
            m_refptr = new size_t(1);
            //成員函數版本
            m_p = m_p?m_p->clone():0;
            //全局函數版本
//            m_p = m_p?clone(m_p):0;
        }
    }      

2 完整代碼示例

#include <iostream>
using std::cout; using  std::endl;
#include <vector>
#include <stdexcept>

//淺層拷貝句柄類
template <typename T>
class ReferenceHandle{
public:
    ReferenceHandle():m_p(nullptr),m_refptr(new std::size_t(1)){}
    ReferenceHandle(T* t):m_p(t),m_refptr(new std::size_t(1)){}
    ReferenceHandle(const ReferenceHandle& h):m_p(nullptr),m_refptr(h.refptr){
        ++*m_refptr;
    }
    ReferenceHandle&operator=(const ReferenceHandle& h){
        ++*m_refptr;
        if(--*m_refptr==0){
            delete m_refptr;
            delete m_p;
        }
        m_refptr = h.m_refptr;
        m_p = h.m_p;
        return *this;
    }
    ~ReferenceHandle(){
        if(--*m_refptr==0){
            delete m_p;
            delete m_refptr;
        }
    }
    operator bool() const{ return  m_p;}
    T&operator*()const {
        if(m_p) return *m_p;
        throw std::runtime_error("unbound Hanlde");
    }
    T*operator->()const {
        if(m_p) return m_p;
        throw std::runtime_error("unbound Hanlde");
    }
private:
    T* m_p;
    std::size_t* m_refptr;
};

//非成員函數版本
//特化一個模版來處理成員函數中沒有clone()的情況(即沒有T::clone())
template <class T>T* clone(const T* tp){
    return tp->clone();
}

template <>
std::vector<char>* clone(const std::vector<char>* vp){
    return new std::vector<char>(*vp);
}
//淺層、深層結合句柄類
template <typename T>
class Ptr{
public:
    //當存在會改變引用值的情況時,配置設定新對象
    void makeUnique(){
        if(*m_refptr != 1){
            --*m_refptr;
            m_refptr = new size_t(1);
            //成員函數版本
//            m_p = m_p?m_p->clone():0;
            //全局函數版本
            m_p = m_p?clone(m_p):0;
        }
    }

    Ptr():m_p(nullptr),m_refptr(new std::size_t(1)){}
    Ptr(T* t):m_p(t),m_refptr(new std::size_t(1)){}
    Ptr(const Ptr& h):m_p(nullptr),m_refptr(h.m_refptr){
        ++*m_refptr;
    }
    Ptr&operator=(const Ptr& h){
        ++*m_refptr;
        if(--*m_refptr==0){
            delete m_refptr;
            delete m_p;
        }
        m_refptr = h.m_refptr;
        m_p = h.m_p;
        return *this;
    }
    ~Ptr(){
        if(--*m_refptr==0){
            delete m_p;
            delete m_refptr;
        }
    }
    operator bool() const{ return  m_p;}
    T&operator*()const {
        if(m_p) return *m_p;
        throw std::runtime_error("unbound Hanlde");
    }
    T*operator->()const {
        if(m_p) return m_p;
        throw std::runtime_error("unbound Hanlde");
    }
private:
    T* m_p;
    std::size_t* m_refptr;
};

class Core{
    friend class ReferenceHandle<Core>;
    virtual Core* clone(){
        return new Core(*this);
    }

public:
    virtual ~Core(){}
    virtual void test(double d, double d2 = 0){cout<<"test(double d1, double d2=0)"<<endl;}
};

class  Derive :public  Core{
    friend class ReferenceHandle<Core>;
public:
    virtual Derive* clone(){
        return new Derive(*this);
    }
    void test(double d1, double d2){cout<<"test(double d1, double d2)"<<endl;}

    typedef std::vector<char>::size_type  size_type;
    //成員函數版本
    char&operator[](size_t i){
        m_data.makeUnique();
        return (*m_data)[i];
    }
private:
    Ptr<std::vector<char>> m_data;
};


int main(){
//    Handle<Core> c(new Derive);
    std::vector<ReferenceHandle<Core>> handle;
    ReferenceHandle<Core> h, h2;
    h = new Core;
    h2 = h;

    return 0;
}      

繼續閱讀