C++箴言:在資源管理類(lèi)中準(zhǔn)備訪問(wèn)裸資源

字號(hào):

資源管理類(lèi)真是太棒了。他們是你防御資源泄漏的防波堤,沒(méi)有這樣的泄漏是設(shè)計(jì)良好的系統(tǒng)的基本特征。在一個(gè)完美的世界中,你可以在所有與資源的交互中依賴(lài)這樣的類(lèi),從來(lái)不需要因?yàn)橹苯釉L問(wèn)*資源(raw resources)而玷污你的手。但是這個(gè)世界并不完美,很多 API 直接涉及資源,所以除非你計(jì)劃堅(jiān)決放棄使用這樣的 API(這種事很少會(huì)成為實(shí)際),否則,你就要經(jīng)常繞過(guò)資源管理類(lèi)而直接處理*資源(raw resources)。
    例如,以前介紹的使用類(lèi)似 auto_ptr 或 tr1::shared_ptr 這樣的智能指針來(lái)持有調(diào)用類(lèi)似 createInvestment 這樣的 factory 函數(shù)的結(jié)果: std::tr1::shared_ptr pInv(createInvestment());
    假設(shè)你打算使用的一個(gè)與 Investment 對(duì)象一起工作的函數(shù)是這樣的:
    int daysHeld(const Investment *pi); // return number of days
    // investment has been held
    你打算像這樣調(diào)用它,
    int days = daysHeld(pInv); // error!
    但是這代碼不能編譯:daysHeld 要求一個(gè)*的 Investment* 指針,但是你傳給它一個(gè)類(lèi)型為 tr1::shared_ptr 的對(duì)象。
    你需要一個(gè)將 RAII 類(lèi)(當(dāng)前情況下是 tr1::shared_ptr)的對(duì)象轉(zhuǎn)化為它所包含的*資源(例如,底層的 Investment*)的方法。有兩個(gè)常規(guī)方法來(lái)做這件事。顯式轉(zhuǎn)換和隱式轉(zhuǎn)換。
    tr1::shared_ptr 和 auto_ptr 都提供一個(gè) get 成員函數(shù)進(jìn)行顯示轉(zhuǎn)換,也就是說(shuō),返回一個(gè)智能指針對(duì)象內(nèi)部的*指針(raw pointer)(或它的一個(gè)副本):
    int days = daysHeld(pInv.get()); // fine, passes the raw pointer
    // in pInv to daysHeld
    就像實(shí)際上的所有智能指針類(lèi)一樣,tr1::shared_ptr 和 auto_ptr 也都重載了指針解引用操作符(pointer dereferencing operators)(operator-> 和 operator*),而這樣就允許隱式轉(zhuǎn)換到底層的*指針(raw pointers):
    class Investment { // root class for a hierarchy
    public: // of investment types
    bool isTaxFree() const;
    ...
    };
    Investment* createInvestment(); // factory function
    std::tr1::shared_ptr // have tr1::shared_ptr
    pi1(createInvestment()); // manage a resource
    bool taxable1 = !(pi1->isTaxFree()); // Access resource
    // via operator->
    ...
    std::auto_ptr pi2(createInvestment()); // have auto_ptr
    // manage a
    // resource
    bool taxable2 = !((*pi2).isTaxFree()); // access resource
    // via operator*
    ...
    因?yàn)橛行r(shí)候有必要取得 RAII 對(duì)象內(nèi)部的*資源,所以一些 RAII 類(lèi)的設(shè)計(jì)者就通過(guò)提供一個(gè)隱式轉(zhuǎn)換函數(shù)來(lái)給剎車(chē)抹油。例如,考慮以下這個(gè) RAII 類(lèi),它要為 C++ API 提供原始狀態(tài)的字體資源:
    FontHandle getFont(); // from C API-params omitted
    // for simplicity
    void releaseFont(FontHandle fh); // from the same C API
    class Font { // RAII class
    public:
    explicit Font(FontHandle fh) // acquire resource;
    : f(fh) // use pass-by-value, because the
    {} // C API does
    ~Font() { releaseFont(f); } // release resource
    private:
    FontHandle f; // the raw font resource
    };