1. 程式人生 > >智慧指標管理通過new建立的物件

智慧指標管理通過new建立的物件

來自《編寫高質量程式碼:改善C++程式的150個建議》讀書筆記

1.auto_ptr

指向一個以new建立的物件,當auto_ptr的生命週期結束時,其所指向的物件之資源也會被自動釋放,且不必顯示地呼叫delete。

#include <memory>
using namespace std;
class A
{
public:
    A() {}
    ~A(){}
    void Hello()
    {
        cout << "Hello Smart Pointer";
    }
};
int main()
{
    auto_ptr
<A> pA(new A()); pA->Hello(); auto_ptr<int> iPtr; // 未指向任何物件,像空指標 if(iPtr.get()==0) // 不指向任何物件判斷 { iPtr.reset(new int(2011)); } auto_ptr<string> sPtr1(new string("Smart Pointer")); auto_ptr<string> sPtr2(sPtr1); // 所有權轉移 if (!sPtr1->empty()) // 判斷emptry時程式會崩潰
cout << *sPtr1 << endl; return 0; }

auto_ptr的資源維護動作是以inline的方式來完成的,在編譯時程式碼會被擴充套件開來,所以使用它並不會犧牲效率。
缺點:

  • auto_ptr物件不可作為STL容器的元素
  • auto_ptr缺少對動態配置而來的陣列的支援;
    auto_ptr<char> pstr(new char[12]); //不支援
    不管什麼時候使用陣列的new操作時,必須要用delete[]來摧毀陣列。因為auto_ptr的解構函式只對非陣列型別起作用。所以陣列是不能被正確摧毀的話,程式的行為是不明確的。
  • auto_ptr在被複制時會發生所有權轉移

2011年9月C++新標準C++11中廢棄了auto_ptr指標,取而代之的是兩個新的指標類:shared_ptr和unique_ptr。shared_ptr是引用計數指標,unique_ptr是用來取代auto_ptr的,提供了auto_ptr的大部分特性,唯一例外的是auto_ptr的不安全、隱性的左值搬移。

2.Boost中的智慧指標

在Boost中的智慧指標有五種:scoped_ptr、scoped_array、shared_ptr、shared_array、weak_ptr,其中最有用的就是shared_ptr,採用了引用計數,並且是執行緒安全的,同時支援擴充套件。
boost::shared_ptr支援STL容器:

typedef boost::shared_ptr<string> CStringPtr;
std::vector<CStringPtr> strVec;
strVec.push_back(CStringPtr(new string("Hello")));

Boost智慧指標同樣支援陣列,boost::scoped_array和boost::shared_array物件指向的是動態配置的陣列。

3.使用智慧指標也應該遵守的規則

規則1:Smart_ptr<T>不同於T*,前者身份是一個物件,後者是指向T類物件的指標,不能盲目地將T*和智慧指標型別Smart_ptr<T>相互轉換。

  • 在建立一個智慧指標時需明確寫出Smart_ptr<T> tPtr(new T)。
  • 禁止將T*賦值給一個智慧指標。
  • 不能採用tPtr=NULL的方式將tPtr置空,應該使用智慧指標類的成員函式。

規則2:不要使用臨時的shared_ptr物件

class A
bool IsAllReady();
void ProcessObject(boost::shared_ptr<A> pA, bool isReady);
ProcessObject(boost::shared_ptr(new A), IsAllReady());

呼叫ProcessObject函式前,C++編譯器要完成三件事:

  1. 執行”new A”。
  2. 呼叫boost::shared_ptr的建構函式。
  3. 呼叫函式IsAllReady()。

因為函式引數求值順序的不確定性,如果呼叫IsAllReady()發生在1、2之間,而又正好出現異常,那麼new A得到的記憶體返回的指標就會丟失,進而發生記憶體洩漏,因為返回的指標沒有存入我們原來期望能阻止資源洩漏的boost::shared_ptr上。避免這種問題的方式,就是不要使用臨時的shared_ptr物件,改用區域性變數來實現。