亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

仿現(xiàn)代C++智能指針實現(xiàn)引用計數(shù)

 更新時間:2024年03月10日 10:00:25   作者:ENG八戒  
這篇文章主要為大家詳細介紹了如何仿現(xiàn)代C++智能指針實現(xiàn)引用計數(shù),文中的示例代碼講解詳細,具有一定的借鑒價值,有需要的小伙伴可以了解下

首先,提個問題,何為引用計數(shù),為什么要去實現(xiàn)引用計數(shù)?

智能指針最大的作用就是協(xié)助開發(fā)者管理內(nèi)存,防止開發(fā)者遺漏釋放或者錯誤釋放已申請的內(nèi)存空間,最大限度保證內(nèi)存安全。使用智能指針可免除非常多的經(jīng)典 C++ 版本帶來的煩惱,比如招人恨的 double free or corruption。

據(jù)微軟內(nèi)部統(tǒng)計,C++ 應(yīng)用的絕大部分問題屬于內(nèi)存安全問題,所以保障內(nèi)存安全的措施真的非常重要。

那么,智能指針是如何保證內(nèi)存安全的呢?

智能指針在初始化時會托管傳入的內(nèi)存空間,在后續(xù)的流程中,一旦識別到被托管的內(nèi)存不再被需要的時候,自動釋放這塊內(nèi)存。

如何識別被托管的內(nèi)存是否還被需要?

通過引用計數(shù),引用計數(shù)就是計數(shù)器,一般用整形變量表示,代表有多少個智能指針已托管該內(nèi)存空間。

已托管的內(nèi)存每增加綁定一個智能指針,該計數(shù)器自動加 1;反之,已托管的內(nèi)存每解綁一個智能指針(比如智能指針超出生命周期,或者主動解除綁定),該計數(shù)器自動減 1。直到計數(shù)器歸 0,這時被托管的內(nèi)存即被判斷為不再需要保留,最后解綁的智能指針負責(zé)釋放該內(nèi)存空間。

其中,可見該計數(shù)器被所有綁定的智能指針共享訪問。

雖然標準庫已經(jīng)提供非常多現(xiàn)成的智能指針可供調(diào)用,但是其中的奧妙還是非常值得我們細細揣摩,下面就開始跟隨筆者一起實現(xiàn)自己的引用計數(shù)幫助類,權(quán)當(dāng)作略微簡陋的自定義智能指針。

先定義兩個類,一個是代表占用內(nèi)存資源的類 Demo,另一個是就是我們自定義的智能指針類 SmartPtr

class Demo
{};

class SmartPtr
{};

資源類附加屬性

由于綁定同一個內(nèi)存資源的所有智能指針是共享訪問該內(nèi)存的,所以可以在類 Demo 中附加定義計數(shù)器 count_,計數(shù)器作為專用屬性應(yīng)該帶有隱私屬性也就是不允許隨意被類外訪問,所以同時應(yīng)該被修飾為 private。

在類 Demo 實例化時,計數(shù)器 count_ 應(yīng)該被清零,然后才能被 SmartPtr 托管。所以要求類 Demo 的所有構(gòu)造函數(shù)都初始化 count_ 為 0。

class Demo
{
public:
    Demo() : count_(0) {};
private:
    unsigned int count_;
};

作為托管方的類 SmartPtr 需要有權(quán)限可以直接讀寫類 Demo 的私有成員 count_,所以在類 Demo 中還要聲明類 SmartPtr 為友元類

class Demo
{
    // ...
private:
    // ...
    friend class SmartPtr;
};

關(guān)于代表資源的類的簡單改造就介紹完了。

自定義智能指針類

智能指針類 SmartPtr 作為托管方,需要實現(xiàn)基本的功能接口,包括托管、解綁、訪問資源成員、獲取資源引用等。

托管

智能指針需要托管某個內(nèi)存資源,那么就需要在內(nèi)部有對應(yīng)的指針指向資源。同樣為了不必要的暴露,這個指針需要用 private 修飾。

class SmartPtr
{
private:
    Demo *p_;
};

在托管資源時,資源對應(yīng)的引用計數(shù)器應(yīng)該自增 1,由于我們定義的智能指針在資源類的內(nèi)部被聲明為友元類,所以智能指針綁定資源時可以直接讀寫資源的計數(shù)器。

智能指針如何綁定資源,或者說如何接收將要被托管的資源呢?

資源未被托管

如果資源當(dāng)前沒有被任何智能指針托管,那么,可以在實例化智能指針對象時,利用智能指針的構(gòu)造函數(shù)接收資源指針,并保存到內(nèi)部指針變量,按照上面的代碼就是保存到變量 p_。

class SmartPtr
{
    // ...
public:
    SmartPtr(Demo *p) : p_(p) {
        ++ p_->count_;
    }
};

分享托管

如果資源當(dāng)前正在被其它智能指針托管,那么,可以從其它的智能指針分享過來。

有兩種分享的方法,一是創(chuàng)建一個新的智能指針來接收其它智能指針的分享,需要用到拷貝構(gòu)造函數(shù),并傳入其它的智能指針的引用實例。

class SmartPtr
{
    // ...
public:
    SmartPtr(const SmartPtr &obj) : p_(obj.p_) {
        ++ p_->count_;
    }
};

二是,如果有個智能指針實例當(dāng)前已經(jīng)托管某個資源,但是需要重新綁定其它資源,并且當(dāng)前托管的資源需要解綁,可以利用拷貝賦值運算符,右側(cè)操作數(shù)就是其它分享資源的智能指針,左側(cè)操作數(shù)是當(dāng)前的智能指針。

解綁當(dāng)前托管的資源,除了要清除原有的資源指針備份,還需要對資源的計數(shù)器減 1,并且判斷計數(shù)器減 1 后是否歸零,如果歸零就需要釋放該資源占用的內(nèi)存

class SmartPtr
{
    // ...
public:
    SmartPtr& operator=(const SmartPtr& sp) {
        Demo *p = p_;
        p_ = sp.p_;
        ++ p_->count_;
        if (0 == (-- p->count_)) {
            delete p;
        }
        return *this;
    }
};

生命周期的結(jié)束

上面提到更換托管資源時,還需要解綁自身原有托管的資源。其實當(dāng)智能指針對象自身的生命周期結(jié)束之時,也就是調(diào)用釋構(gòu)函數(shù)時,也需要解綁自身原有托管的資源,這時的解綁主要做的就是對資源的計數(shù)器減 1,并且判斷計數(shù)器減 1 后是否歸零,如果歸零就需要釋放該資源占用的內(nèi)存

class SmartPtr
{
    // ...
public:
    ~SmartPtr() {
        if (0 == (-- p_->count_)) {
            delete p_;
        }
    }
};

成員訪問

智能指針在托管資源后,資源內(nèi)部的成員應(yīng)該能通過智能指針來訪問,正如前面介紹資源類時,在資源類內(nèi)部聲明智能指針為友元類。通過智能指針來訪問資源類內(nèi)部成員的形式,應(yīng)該類似對象的指針訪問對象成員,需要通過重寫智能指針的成員訪問運算符來實現(xiàn)

class SmartPtr
{
    // ...
public:
    Demo* operator->() {
        return p_;
    }
};

operator-> () 是一元右綴操作符,重寫了類成員訪問運算符,返回被托管的資源指針。

當(dāng)智能指針對象調(diào)用該操作符時,比如 p 被聲明為智能指針實例對象,被托管的資源所屬類包含成員 m,那么 p->m 會被編譯器解析成 ((p.operator->)->m。

獲取資源引用

一般通過對象指針獲取對象引用時,是通過 * 運算符。類似地,需要獲取被托管資源對象的引用,可以重寫 * 運算符實現(xiàn)

class SmartPtr
{
    // ...
public:
    Demo& operator*() {
        return *p_;
    }
};

避免暴露裸指針

一般不推薦直接調(diào)用資源類的裸指針,盡量避免重寫智能指針的操作符以返回被托管資源的指針,因為暴露的裸指針會被意外地使用而破壞引用計數(shù)的機制,最終破壞實現(xiàn)內(nèi)存安全的努力。

而上面在設(shè)計資源類時,仍然依賴使用 new 操作符創(chuàng)建資源實例并返回裸指針,這無疑是一顆定時炸彈。為了隱藏好裸指針,可以把構(gòu)造函數(shù)聲明為 private,并且添加靜態(tài)成員接口 create() 返回智能指針對象

// .h
class SmartPtr;
class Demo
{
public:
    static SmartPtr create();
private:
    Demo() : count_(0) {};
    unsigned int count_;
    friend class SmartPtr;
};
// ...

// .cpp
SmartPtr Demo::create() {
    return new Demo();
}

為什么接口 Demo::create() 內(nèi)部直接 return 類 Demo 對象指針而不是 SmartPtr 對象?

因為前面實現(xiàn)類 SmartPtr 時,它的構(gòu)造函數(shù)就有輸入 Demo 指針的重載形式。所以接口 Demo::create() 聲明返回類型為 SmartPtr 對象時,如果直接返回類 Demo 對象指針,就會隱式調(diào)用類 SmartPtr 的對應(yīng)構(gòu)造函數(shù)創(chuàng)建實例對象并返回。

基于上面的設(shè)計結(jié)果,當(dāng)需要在堆里創(chuàng)建 Demo 實例時,內(nèi)存安全的使用方式就可以是這樣子

SmartPtr ptr(Demo::create());

簡簡單單的思路分析如上,其中實現(xiàn)方法利用的是指針語義。

以上就是仿現(xiàn)代C++智能指針實現(xiàn)引用計數(shù)的詳細內(nèi)容,更多關(guān)于C++引用計數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論