關於std:auto_ptr

很多人聽說過標準auto_ptr智能指針機制,但並不是每個人都天天使用它。這真是個遺憾,因爲auto_ptr優雅地解決了C++設計和編碼中常見的問題,正確地使用它可以生成健壯的代碼。本文闡述瞭如何正確運用auto_ptr來讓你的代碼更加安全——以及如何避免對auto_ptr危險但常見的誤用,這些誤用會引發間斷性發作、難以診斷的bug。

1.爲什麼稱它爲“自動”指針?
auto_ptr只是衆多可能的智能指針之一。許多商業庫提供了更復雜的智能指針,用途廣泛而令人驚異,從管理引用的數量到提供先進的代理服務。可以把標準C++ auto_ptr看作智能指針的Ford Escort(elmar注:可能指福特的一種適合家居的車型):一個簡易、通用的智能指針,它不包含所有的小技巧,不像專用的或高性能的智能指針那麼奢華,但是它可以很好的完成許多普遍的工作,它很適合日常性的使用。

auto_ptr所做的事情,就是動態分配對象以及當對象不再需要時自動執行清理。這裏是一個簡單的代碼示例,沒有使用auto_ptr所以不安全:
    // 示例 1(a): 原始代碼
    //
    void f()
    {
      T* pt( new T );

      /*...更多的代碼...*/

      delete pt;
    }

我們大多數人每天寫類似的代碼。如果f()函數只有三行並且不會有任何意外,這麼做可能挺好的。但是如果f()從不執行delete語句,或者是由於過早的返回,或者是由於執行函數體時拋出了異常,那麼這個被分配的對象就沒有被刪除,從而我們產生了一個經典的內存泄漏。

能讓示例1(a)安全的簡單辦法是把指針封裝在一個“智能的”類似於指針的對象裏,這個對象擁有這個指針並且能在析構時自動刪除這個指針所指的對象。因爲這個智能指針可以簡單的當成一個自動的對象(這就是說,它出了作用域時會自動毀滅),所以很自然的把它稱之爲“智能”指針:

    // 示例 1(b): 安全代碼, 使用了auto_ptr
    //
    void f()
    {
      auto_ptr<T> pt( new T );

      /*...更多的代碼...*/

    } // 酷: 當pt出了作用域時析構函數被調用,
      // 從而對象被自動刪除

現在代碼不會泄漏T類型的對象,不管這個函數是正常退出還是拋出了異常,因爲pt的析構函數總是會在出棧時被調用。清理會自動進行。

最後,使用一個auto_ptr就像使用一個內建的指針一樣容易,而且如果想要“撤銷”資源,重新採用手動的所有權,我們只要調用release():

    // 示例 2: 使用一個 auto_ptr
    //
    void g()
    {
      T* pt1 = new T;
      // 現在,我們有了一個分配好的對象

      // 將所有權傳給了一個auto_ptr對象
      auto_ptr<T> pt2( pt1 );

      // 使用auto_ptr就像我們以前使用簡單指針一樣
      *pt2 = 12;       // 就像 "*pt1 = 12;"
      pt2->SomeFunc(); // 就像 "pt1->SomeFunc();"

      // 用get()來獲得指針的值
      assert( pt1 == pt2.get() );

      // 用release()來撤銷所有權
      T* pt3 = pt2.release();

      // 自己刪除這個對象,因爲現在
      // 沒有任何auto_ptr擁有這個對象
      delete pt3;

    } // pt2不再擁有任何指針,所以不要
      // 試圖刪除它...ok,不要重複刪除

最後,我們可以使用auto_ptr的reset()函數來重置auto_ptr使之擁有另一個對象。如果這個auto_ptr已經擁有了一個對象,那麼,它會先刪除已經擁有的對象,因此調用reset()就如同銷燬這個auto_ptr,然後新建一個並擁有一個新對象:

    // 示例 3: 使用reset()
    //
    void h()
    {
      auto_ptr<T> pt( new T(1) );

      pt.reset( new T(2) );
        // 刪除由"new T(1)"分配出來的第一個T

    } // 最後,pt出了作用域,
      // 第二個T也被刪除了 

發佈了32 篇原創文章 · 獲贊 1 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章