欧美性猛交黑人xxxx,成人毛片一区二区三区,久久综合九色综合精品,男的把j放进女人下面视频免费

C++箴言:謹慎考慮資源管理類的拷貝行為

  • 發(fā)布于:2023-09-05
  • 191 人圍觀
  在上一篇文章中介紹了作為資源管理類支柱的 Resource Acquisition Is Initialization (RAII) 原則,并描述了 auto_ptr 和 tr1::shared_ptr 在基于堆的資源上運用這一原則的表現(xiàn)。并非所有的資源都是基于堆的,然而,對于這樣的資源,像 auto_ptr 和 tr1::shared_ptr 這樣的智能指針通常就不像 resource handlers(資源管理者)那樣合適。在這種情況下,有時,你可能要根據(jù)你自己的需要去創(chuàng)建你自己的資源管理類。

  例如,假設你使用 C API 提供的 lock 和 unlock 函數(shù)去操縱 Mutex 類型的互斥體對象:

void lock(Mutex *pm); // lock mutex pointed to by pm

void unlock(Mutex *pm); // unlock the mutex

  為了確保你從不會忘記解鎖一個被你加了鎖的 Mutex,你希望創(chuàng)建一個類來管理鎖。RAII 原則規(guī)定了這樣一個類的基本結(jié)構(gòu),通過構(gòu)造函數(shù)獲取資源并通過析構(gòu)函數(shù)釋放它:

class Lock {
  public:
   explicit Lock(Mutex *pm)
   : mutexPtr(pm)
   { lock(mutexPtr); } // acquire resource
 
   ~Lock() { unlock(mutexPtr); } // release resource

  private:
   Mutex *mutexPtr;
};

  客戶按照 RAII 風格的慣例來使用 Lock:

Mutex m; // define the mutex you need to use
...
{ // create block to define critical section
  Lock ml(&m); // lock the mutex
  ... // perform critical section operations

} // automatically unlock mutex at end
// of block

  這沒什么問題,但是如果一個 Lock 對象被拷貝應該發(fā)生什么?

Lock ml1(&m); // lock m

Lock ml2(ml1); // copy ml1 to ml2-what should
// happen here?

  這是一個更一般問題的特定實例,每一個 RAII 類的作者都要面臨這樣的問題:當一個 RAII 對象被拷貝的時候應該發(fā)生什么?大多數(shù)情況下,你可以從下面各種可能性中挑選一個:

  禁止拷貝。在很多情況下,允許 RAII 被拷貝是沒有意義的。這對于像 Lock 這樣類很可能是正確的,因為同步的基本要素的“副本”很少有什么意義。當拷貝對一個 RAII 類沒有什么意義的時候,你應該禁止它。Item 6 解釋了如何做到這一點。聲明拷貝操作為私有。對于 Lock,看起來也許像這樣:

class Lock: private Uncopyable { // prohibit copying - see
public: // Item 6
... // as before
};

  對底層的資源引用計數(shù)。有時人們需要的是保持一個資源直到最后一個使用它的對象被銷毀。在這種情況下,拷貝一個 RAII 對象應該增加引用這一資源的對象的數(shù)目。這也就是使用 tr1::shared_ptr 時“拷貝”的含意。

  通常,RAII 類只需要包含一個 tr1::shared_ptr 數(shù)據(jù)成員就能夠?qū)崿F(xiàn)引用計數(shù)的拷貝行為。例如,如果 Lock 要使用引用計數(shù),他可能要將 mutexPtr 的類型從 Mutex* 改變?yōu)?tr1::shared_ptr<Mutex>。不幸的是,tr1::shared_ptr 的缺省行為是當它所指向的東西的引用計數(shù)變?yōu)?0 的時候?qū)⑺鼊h除,但這不是我們要的。當我們使用 Mutex 完畢后,我們想要將它解鎖,而不是將它刪除。

  幸運的是,tr1::shared_ptr 允許一個 "deleter" 規(guī)范——當引用計數(shù)變?yōu)?0 時調(diào)用的一個函數(shù)或者函數(shù)對象。(這一功能是 auto_ptr 所沒有的,auto_ptr 總是刪除它的指針。)deleter 是 tr1::shared_ptr 的構(gòu)造函數(shù)的可選的第二個參數(shù),所以,代碼看起來就像這樣:

class Lock {
public:
  explicit Lock(Mutex *pm) // init shared_ptr with the Mutex
  : mutexPtr(pm, unlock) // to point to and the unlock func
  { // as the deleter

   lock(mutexPtr.get()); // see Item 15 for info on "get"
  }
private:
  std::tr1::shared_ptr<Mutex> mutexPtr; // use shared_ptr
}; // instead of raw pointer

  在這個例子中,注意 Lock 類是如何不再聲明一個析構(gòu)函數(shù)的。那是因為它不再需要。Item 5 解釋了一個類的析構(gòu)函數(shù)(無論它是編譯器生成還是用戶定義)會自動調(diào)用這個類的非靜態(tài)(non-static)數(shù)據(jù)成員的析構(gòu)函數(shù)。在本例中,就是 mutexPtr。但是,當互斥體的引用計數(shù)變?yōu)?0 時,mutexPtr 的析構(gòu)函數(shù)會自動調(diào)用的是 tr1::shared_ptr 的 deleter ——在此就是 unlock。(看過這個類的源代碼的人多半意識到需要增加一條注釋表明你并非忘記了析構(gòu),而只是依賴編譯器生成的缺省行為。)

  拷貝底層的資源。有時就像你所希望的你可以擁有一個資源的多個副本,唯一的前提是你需要一個資源管理類確保當你使用完它之后,每一副本都會被釋放。在這種情況下,拷貝一個資源管理對象也要同時拷貝被它隱藏的資源。也就是說,拷貝一個資源管理類需要完成一次“深層拷貝”。

  某些標準 string 類型的實現(xiàn)是由堆內(nèi)存的指針組成,堆內(nèi)存中存儲著組成那個 string 的字符。這樣的字符串對象包含指向堆內(nèi)存的指針。當一個 string 對象被拷貝,這個副本應該由那個指針和它所指向的內(nèi)存組成。這樣的 strings 表現(xiàn)為深層拷貝。

  傳遞底層資源的所有權(quán)。在某些特殊場合,你可能希望確保只有一個 RAII 對象引用一個未加工的資源,而當這個 RAII 對象被拷貝的時候,資源的所有權(quán)從被拷貝的對象傳遞到拷貝對象。就像上一篇文章所說明的,這就是使用 auto_ptr 時“拷貝”的含意。

  拷貝函數(shù)(copying functions)(拷貝構(gòu)造函數(shù)和拷貝賦值運算符)可能是由編譯器生成的,所以除非編譯器生成的版本所做的事正是你所要的,你應該自己編寫它們。在某些情況下,你也要支持這些函數(shù)的泛型化版本。

  Things to Remember

  ·拷貝一個 RAII 對象必須拷貝它所管理的資源,所以資源的拷貝行為決定了 RAII 對象的拷貝行為。

  ·普通的 RAII 類的拷貝行為不接受拷貝和進行引用計數(shù),但是其它行為是有可能的。
萬企互聯(lián)
標簽: