智慧指標管理通過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++編譯器要完成三件事:
- 執行”new A”。
- 呼叫boost::shared_ptr的建構函式。
- 呼叫函式IsAllReady()。
因為函式引數求值順序的不確定性,如果呼叫IsAllReady()發生在1、2之間,而又正好出現異常,那麼new A得到的記憶體返回的指標就會丟失,進而發生記憶體洩漏,因為返回的指標沒有存入我們原來期望能阻止資源洩漏的boost::shared_ptr上。避免這種問題的方式,就是不要使用臨時的shared_ptr物件,改用區域性變數來實現。