青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

洛譯小筑

別來無恙,我的老友…
隨筆 - 45, 文章 - 0, 評論 - 172, 引用 - 0
數據加載中……

[ECPP讀書筆記 條目15] 要為資源管理類提供對原始資源的訪問權

資源管理類的特征是振奮人心的。它構筑起一道可靠的屏障,可有效地防止資源泄漏。能否預防資源泄漏是“系統的設計方案是否優異”的一個基本評判標準。在完美的世界里,你應該依靠資源管理類來完成所有的與資源交互的工作,而永遠不要直接訪問原始資源。然而世界并不是完美的。由于許多API會直接引用資源,因此除非你發誓不使用這樣的API(這樣做顯得太不實際了),否則,你必須繞過資源管理類,然后在需要的時候及時手工處理原始資源。

舉例說,條目13中引入了下面的做法:使用諸如auto_ptr或者tr1::shared_ptr這樣的智能指針來保存諸如createInvestment的工廠函數的返回值:

std::tr1::shared_ptr<Investment> pInv(createInvestment());

                                       // 來自條目13

假設,當你使用Investment對象時,你需要一個這樣的函數:

int daysHeld(const Investment *pi);   // 返回持有投資的天數

你可能希望這樣來調用它:

int days = daysHeld(pInv);            // 錯!

但是這段代碼無法通過編譯:因為daysHeld需要一個原始的Investment*指針,但是你傳遞給它的對象的類型卻是tr1::shared_ptr<Investment>

你需要一個渠道來將一個RAII類的對象(在上面的示例中是tr1::shared_ptr)轉變為它所包含的原始資源(比如說,原始的Investment*)。這里實現這一轉變有兩個一般的方法:顯式轉換和隱式轉換。

tr1::shared_ptrauto_ptr都提供了一個get成員函數來進行顯式轉換,也就是說,返回一個智能指針對象中的原始指針(的副本):

int days = daysHeld(pInv.get());          // 工作正常,
                                                         // pInv中的原始指針傳遞給daysHeld

似乎所有的智能指針類,包括tr1::shared_ptrauto_ptr等等,都會重載指針解析運算符(operator->operator*),這便使得你可以對原始指針進行隱式轉換:

class Investment {                 // 投資類型的層次結構中
                                                   // 最為根基的類

public:

  bool isTaxFree() const;

  ...

};

 

Investment* createInvestment();   // 工廠函數

 

std::tr1::shared_ptr<Investment> pi1(createInvestment());
                                                  // 使用tr1::shared_ptr管理資源

bool taxable1 = !(pi1->isTaxFree());
                                                  // 通過operator->訪問資源

...

 

std::auto_ptr<Investment> pi2(createInvestment());
                                                  // 使用auto_ptr管理資源

bool taxable2 = !((*pi2).isTaxFree());
                                                  // 通過operator*訪問資源

...

由于某些時刻你需要獲取一個RAII對象中的原始資源,所以一些RAII類的設計者使用了一個小手段來使系統正常運行,那就是:提供一個隱式轉換函數。舉例說,以下是一個C版本API中提供的處理字體的RAII類:

FontHandle getFont();              // 來自一個C版本API
                                                   // 省略參數表以簡化代碼

 

void releaseFont(FontHandle fh);     // 來自同一個C版本API

 

class Font {                       // RAII

public:
  explicit Font(FontHandle fh)     // 通過傳值獲取資源
   : f(fh)                          // 因為該C版本API這樣做

  {}

  ~Font() { releaseFont(f); }      // 釋放資源 

private:
  FontHandle f;                    // 原始的字體資源

};

假設這里有一個大型的與字體相關的C版本API通過FontHandle解決所有問題,那么把Font對象轉換為FontHandle的操作將十分頻繁。Font類可以提供一個顯式轉換函數,比如get

class Font {

public:

  ...

  FontHandle get() const { return f; }
                                                   // 進行顯式轉換的函數

  ...

};

遺憾的是,這樣做使得客戶在每次與這一API通信時都要調用一次get

void changeFontSize(FontHandle f, int newSize);
                                                   // 來自該C語言API

Font f(getFont());
int newFontSize;

...

changeFontSize(f.get(), newFontSize);
                                                   // 顯式轉換:從FontFontHandle

一些程序員可能會發現,由于使用這個類要求我們始終提供上述示例中的那種顯式轉換,這一點很糟糕,足夠讓他們拒絕使用這個類了。同時這一設計又增加了字體資源泄漏的可能性,這與Font類的設計初衷是完全相悖的。

有一個替代方案,讓Font提供一個可隱式轉換為Fonthandle的函數:

class Font {

public:

  ...

  operator FontHandle() const { return f; }
                                                    // 進行隱式轉換的函數

 

  ...

};

這使得調用這一C版本API的工作變得簡潔而且自然:

Font f(getFont());

int newFontSize;

...

 

changeFontSize(f, newFontSize);   // 隱式轉換:從FontFontHandle

 

隱式轉換會帶來一定的負面效應:它會增加出錯的可能。比如說,一個客戶在一個需要Font的地方意外地創建了一個FontHandle

Font f1(getFont());

...

FontHandle f2 = f1;                // 啊哦!本想復制一個Font對象,
                                                   // 但是卻卻將f1隱式轉換為其原始的
                                                   // FontHandle,然后復制它

現在程序中有一個FontHandle資源正在由Font對象f1來管理,但是仍然可以通過f2直接訪問FontHandle資源。這是很糟糕的。比如說,當f1被銷毀時,字體就會被釋放,f2將無法被銷毀。

是為RAII類提供顯式轉換為潛在資源的方法,還是允許隱式轉換,上面兩個問題的答案取決于RAII類設計用于完成的具體任務,及其被使用的具體環境。最好的設計方案應該遵循條目18的建議,讓接口更容易被正確使用,而不易被誤用。通常情況下,定義一個類似于get的顯式轉換函數是一個較好的途徑,應為它可以使非故意類型轉換的可能性降至最低。然而,一些時候使用隱式類型轉換顯得更加自然,人們更趨向于使用它。

你可能已經發現,讓一個函數返回一個RAII類內部的原始資源是違背封裝性原則的。的確是這樣,乍看上去這簡直就是設計災難,但是它實際上并沒有那么糟糕。RAII類并不是用來封裝什么的,它們是用來確保一些特別的操作能夠得以執行的,那就是資源釋放。如果需要,資源封裝工作可以放在這一主要功能的最頂端,但是這并不是必需的。另外,一些RAII類結合了實現封裝的嚴格性和原始資源封裝的寬松性。比如tr1::shared_ptr對其引用計數機制進行了整體封裝,但是它仍然為其所包含的原始指針提供了方便的訪問方法。就像其它設計優秀的類一樣,它隱藏了客戶不需要關心的內容,但是它使得客戶的確需要訪問的部分對其可見。

時刻牢記

API通常需要訪問原始資源,所以每個RAII類都應該提供一個途徑來獲取它所管理的資源。

訪問可以通過顯式轉換或隱式轉換來實現。一般情況下,顯式轉換更安全,而隱式轉換對于客戶來說更方便。

posted on 2007-05-13 20:54 ★ROY★ 閱讀(836) 評論(0)  編輯 收藏 引用 所屬分類: Effective C++

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            夜夜嗨av一区二区三区四区| 欧美激情四色| 亚洲欧美视频一区二区三区| 国产精品日日摸夜夜摸av| 亚洲精品国产精品乱码不99按摩| 欧美v亚洲v综合ⅴ国产v| 久久久久久一区二区三区| 在线观看欧美日韩国产| 亚洲国产天堂久久综合| 欧美日韩三级| 欧美亚洲系列| 久久理论片午夜琪琪电影网| 亚洲国产专区校园欧美| 亚洲精品专区| 国产亚洲欧美一区| 亚洲国产精品热久久| 国产精品天美传媒入口| 欧美二区乱c少妇| 欧美精品亚洲精品| 久久精品欧美| 欧美日韩亚洲一区二区三区| 久久夜色精品一区| 欧美日韩亚洲综合| 你懂的亚洲视频| 国产精品h在线观看| 欧美电影在线播放| 国产日韩欧美在线视频观看| 亚洲欧洲精品一区二区三区波多野1战4 | 国产区亚洲区欧美区| 欧美高清hd18日本| 国产精品免费看片| 亚洲国产一区二区三区a毛片| 国产精品日韩在线观看| 亚洲精品少妇| 亚洲二区视频在线| 午夜精品久久久久影视| 亚洲午夜精品视频| 欧美成人蜜桃| 久久综合影音| 国产人成精品一区二区三| 中日韩美女免费视频网站在线观看| 在线观看av一区| 欧美在线免费观看| 久久国产一区二区三区| 欧美日韩综合视频| 亚洲精品无人区| 亚洲精品欧洲| 欧美本精品男人aⅴ天堂| 欧美gay视频| 狠狠色狠狠色综合日日小说| 亚洲免费视频观看| 性一交一乱一区二区洋洋av| 欧美视频一区二区三区在线观看 | 亚洲伊人久久综合| 亚洲一级黄色片| 欧美日产一区二区三区在线观看| 欧美黄色视屏| 亚洲国产天堂久久综合网| 久久精品夜色噜噜亚洲a∨| 久久国产成人| 激情久久久久久久| 久久久99久久精品女同性| 久久嫩草精品久久久精品| 韩国一区二区在线观看| 久久久久久久成人| 欧美在线啊v一区| 99热免费精品| 欧美激情视频一区二区三区在线播放| 欧美ed2k| 99精品视频一区二区三区| 欧美日韩色综合| 一区二区三区产品免费精品久久75 | 欧美一区激情| 国产午夜久久久久| 久久久国产一区二区| 久久综合中文| 日韩一级裸体免费视频| 欧美日韩在线视频观看| 亚洲自拍16p| 久久综合网色—综合色88| 亚洲二区视频在线| 欧美日韩一区二区三区在线视频| 中文久久精品| 久久综合网色—综合色88| 亚洲美女诱惑| 国产日韩亚洲| 久久伊人免费视频| 日韩一区二区精品葵司在线| 欧美一区二区观看视频| 亚洲成人在线观看视频| 欧美日韩国产色站一区二区三区| 亚洲在线免费观看| 欧美成人一区二免费视频软件| 在线一区日本视频| 国产一区视频网站| 欧美日韩成人激情| 欧美一区视频| 亚洲九九九在线观看| 久久一二三四| 亚洲一区二区四区| 亚洲国产91| 国产欧美在线视频| 欧美精品一区三区在线观看| 香蕉成人啪国产精品视频综合网| 最新日韩精品| 欧美aaa级| 欧美亚洲在线观看| 日韩视频在线免费观看| 好看的日韩视频| 欧美午夜影院| 欧美激情亚洲精品| 久久久天天操| 先锋影音久久| 亚洲无线一线二线三线区别av| 欧美99在线视频观看| 久久久久久久999| 亚洲欧美日本伦理| 一区二区日韩欧美| 亚洲精品国产品国语在线app| 国产欧美日韩在线播放| 欧美日韩免费观看中文| 欧美不卡视频一区| 久久夜色精品国产噜噜av| 午夜精品久久久久久99热| 99精品视频一区二区三区| 亚洲高清二区| 欧美国产精品劲爆| 麻豆精品视频| 免费亚洲电影| 你懂的亚洲视频| 免费在线看一区| 欧美成人精品h版在线观看| 欧美制服第一页| 欧美亚洲综合久久| 久久成人精品| 久久激情视频久久| 亚洲欧美激情一区| 亚洲欧美激情诱惑| 亚洲综合电影| 性欧美18~19sex高清播放| 亚洲欧美日韩直播| 亚洲欧美三级伦理| 久久成人免费日本黄色| 久久久久久精| 暖暖成人免费视频| 欧美激情麻豆| 欧美三级电影大全| 国产精品xvideos88| 国产精品自拍三区| 国产一区二区三区的电影| 黑人操亚洲美女惩罚| 亚洲国产美女| 一本久久综合亚洲鲁鲁五月天| 一区二区三区精品久久久| 亚洲综合首页| 久久久高清一区二区三区| 免播放器亚洲一区| 亚洲国产欧美一区二区三区久久| 亚洲日本中文| 亚洲免费在线看| 久久精彩视频| 欧美久久电影| 国产日韩欧美麻豆| 亚洲国产视频直播| 亚洲男人的天堂在线aⅴ视频| 久久精品99国产精品日本| 欧美**人妖| 在线亚洲伦理| 久久精品一区二区国产| 欧美交受高潮1| 国产精品一区二区三区久久 | 欧美日韩国产小视频| 国产精品毛片va一区二区三区| 激情久久久久| 亚洲一区三区视频在线观看| 久久婷婷久久一区二区三区| 日韩视频一区二区三区在线播放免费观看| 亚洲午夜三级在线| 美女视频黄免费的久久| 国产精品久久久久aaaa樱花| 亚洲大胆女人| 欧美一区影院| 99精品欧美| 久久综合久久久| 国产乱码精品一区二区三区av| 最近中文字幕mv在线一区二区三区四区| 亚洲网站在线| 免费看av成人| 午夜精品久久久久久久白皮肤| 欧美国产在线电影| 伊人夜夜躁av伊人久久| 性视频1819p久久| 99精品久久久| 欧美精品18+| 亚洲国产岛国毛片在线| 久久久久久69| 新片速递亚洲合集欧美合集| 欧美日韩三级视频| 99视频精品全国免费| 欧美福利视频在线观看|