欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

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

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

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

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

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

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

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

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

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

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

class Demo
{};

class SmartPtr
{};

資源類附加屬性

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

在類 Demo 實(shí)例化時(shí),計(jì)數(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 作為托管方,需要實(shí)現(xiàn)基本的功能接口,包括托管、解綁、訪問資源成員、獲取資源引用等。

托管

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

class SmartPtr
{
private:
    Demo *p_;
};

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

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

資源未被托管

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

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

分享托管

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

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

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

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

解綁當(dāng)前托管的資源,除了要清除原有的資源指針備份,還需要對(duì)資源的計(jì)數(shù)器減 1,并且判斷計(jì)數(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é)束

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

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

成員訪問

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

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

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

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

獲取資源引用

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

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

避免暴露裸指針

一般不推薦直接調(diào)用資源類的裸指針,盡量避免重寫智能指針的操作符以返回被托管資源的指針,因?yàn)楸┞兜穆阒羔槙?huì)被意外地使用而破壞引用計(jì)數(shù)的機(jī)制,最終破壞實(shí)現(xiàn)內(nèi)存安全的努力。

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

// .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 對(duì)象指針而不是 SmartPtr 對(duì)象?

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

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

SmartPtr ptr(Demo::create());

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

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

相關(guān)文章

最新評(píng)論