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

洛譯小筑

別來無恙,我的老友…
隨筆 - 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>
            亚洲高清二区| 欧美成ee人免费视频| 午夜精品一区二区三区在线 | 欧美在线网址| 久久一区欧美| 中文成人激情娱乐网| 影音先锋日韩资源| 亚洲国产欧美一区| 一本久道久久久| 亚洲永久网站| 久久人人九九| 亚洲福利在线视频| 欧美激情视频一区二区三区免费 | 亚洲深夜福利网站| 午夜精品久久久久久久| 欧美伊人久久久久久午夜久久久久| 午夜精品在线视频| 免费不卡在线观看av| 亚洲精品女av网站| 亚洲免费精彩视频| 久久精品123| 欧美日韩第一页| 国产精品一区二区视频| 亚洲高清不卡在线观看| 亚洲视频在线一区| 久久一区激情| 在线亚洲成人| 午夜精品理论片| 欧美精品国产一区| 国产亚洲人成网站在线观看| 一区二区三区视频在线播放| 久久永久免费| 午夜精品免费在线| 欧美日韩国产va另类| 国产欧美日韩中文字幕在线| 一本久久a久久免费精品不卡| 性做久久久久久免费观看欧美 | 欧美中文字幕在线观看| 欧美成人按摩| 午夜欧美不卡精品aaaaa| 欧美激情视频在线播放| 国产在线视频不卡二| 亚洲欧美日韩在线综合| 91久久国产综合久久91精品网站| 久久精品夜夜夜夜久久| 国产精品日韩欧美大师| 一区二区欧美视频| 亚洲片区在线| 欧美成人免费全部| 在线播放一区| 久久综合网色—综合色88| 性色av一区二区三区在线观看| 亚洲电影第1页| 久久久一本精品99久久精品66| 亚洲精品影视在线观看| 久久手机免费观看| 国产亚洲一区二区三区在线观看| 制服诱惑一区二区| 91久久精品www人人做人人爽| 久久全球大尺度高清视频| 国内欧美视频一区二区| 午夜精品久久久久久久久久久久久| 日韩午夜精品视频| 欧美三区美女| 亚洲尤物精选| 亚洲欧美视频在线观看| 国产伦精品一区二区三区免费迷| 亚洲尤物精选| 亚洲欧美大片| 国产午夜精品美女视频明星a级| 亚洲欧美精品一区| 亚洲欧美一区二区原创| 国产一区二区三区四区三区四| 久久久精品动漫| 久久性色av| 亚洲免费大片| 夜夜嗨av一区二区三区四区| 国产精品午夜电影| 久久免费国产| 欧美大片专区| 欧美一级大片在线观看| 久久噜噜噜精品国产亚洲综合| 亚洲国产美国国产综合一区二区| 亚洲黄色影片| 国产精品久久777777毛茸茸| 久久久久久久综合日本| 免费的成人av| 午夜精品久久久| 久久一区视频| 欧美亚洲三级| 欧美成人中文| 欧美中文在线观看| 蜜臀av国产精品久久久久| 亚洲一区二区三区涩| 久久精品最新地址| 一本色道久久综合狠狠躁篇的优点| 亚洲在线观看免费视频| 亚洲激情亚洲| 欧美在线高清视频| 亚洲小说欧美另类社区| 久久综合九色综合欧美就去吻| 亚洲性图久久| 欧美1区3d| 久久国产福利| 欧美视频观看一区| 欧美成人精品影院| 国产欧美日韩精品a在线观看| 亚洲国产精品久久久久秋霞蜜臀| 国产毛片久久| 一道本一区二区| 亚洲精品在线视频| 久久久久在线观看| 欧美一区国产在线| 欧美日韩视频在线一区二区| 欧美在线视频观看| 一区二区高清视频在线观看| 亚洲精品少妇网址| 激情另类综合| 午夜伦欧美伦电影理论片| 亚洲影音一区| 欧美日韩在线免费观看| 欧美激情aⅴ一区二区三区| 国产美女一区| 亚洲一区二区三区乱码aⅴ| 夜夜嗨av一区二区三区网站四季av| 久久不射中文字幕| 亚洲欧美国产三级| 欧美午夜精品一区二区三区| 亚洲精品人人| 日韩亚洲欧美一区二区三区| 免费视频一区| 欧美1区2区3区| 亚洲大胆美女视频| 久久综合狠狠综合久久综合88| 久久亚洲影院| 有坂深雪在线一区| 久久九九精品99国产精品| 久久美女性网| 亚洲国产精品欧美一二99| 美女图片一区二区| 亚洲国产精品女人久久久| 日韩一级在线观看| 欧美人与禽性xxxxx杂性| 亚洲精品小视频| 亚洲一区在线直播| 国产精品自拍网站| 久久aⅴ乱码一区二区三区| 老鸭窝91久久精品色噜噜导演| 在线观看欧美日韩国产| 欧美sm视频| 夜夜嗨av一区二区三区中文字幕| 亚洲尤物在线视频观看| 国产精品美女999| 欧美一区三区二区在线观看| 噜噜噜噜噜久久久久久91| 亚洲日本一区二区| 欧美日韩精品一区二区三区| 亚洲一区二区三区国产| 久久精品亚洲一区二区| 在线免费不卡视频| 欧美精品性视频| 亚洲欧美制服中文字幕| 美国十次了思思久久精品导航| 亚洲欧洲一区| 国产精品色婷婷| 久久综合精品国产一区二区三区| 一本色道久久综合狠狠躁篇怎么玩| 久久超碰97中文字幕| 亚洲精品极品| 国产欧美日韩三级| 欧美电影免费观看高清完整版| 日韩午夜激情| 蜜桃av一区| 亚洲欧美一区二区在线观看| 亚洲成色999久久网站| 国产精品久久久久久久第一福利 | 欧美精品激情在线观看| 午夜激情亚洲| 91久久线看在观草草青青| 性色一区二区| 99精品久久免费看蜜臀剧情介绍| 国产精品天天摸av网| 亚洲欧美激情诱惑| 欧美激情中文不卡| 午夜老司机精品| 一区二区三区精品在线 | 一区二区三区在线高清| 欧美日韩日本国产亚洲在线| 久久精品综合网| 亚洲一区二区三区在线看| 欧美成人激情视频| 久久爱91午夜羞羞| 在线视频日韩| 亚洲日韩视频| 国产日韩欧美精品一区| 欧美日韩在线播放| 欧美国产精品人人做人人爱| 久久国产精品久久国产精品| 午夜视频一区| 欧美一级久久|