如果使用智能指針, 如果程序塊過早的結束, 智能指針能保證在內存不再需要時進行釋放. (特別是在有多個出口的函數中 -- 雖然應盡量避免設計這樣的函數, 但凡事總有例外 -- 此時使用智能指針來自動釋放內存是非常方便的)
對於異常處理來說, 考慮下面兩個函數, 當程序發生異常時, 智能指針也能正確的釋放內存.
void f3()
{
int* p = new int(10);
throw "some error infomations";
delete p;
}
void f4()
{
std::shared_ptr<int> sp = std::make_shared<int>(10);
throw "some error infomations";
}
C++智能指針使用時需要注意的事項, C++11中已經廢棄了 auto_ptr, 因此不再討論其用法, 無特殊說明, 下面的事項對 auto_ptr 而言, 可能是不正確的.
(1) 不要把一個原生指針給多個智能指針對象管理, 對所有的智能指針對象都成立
int* p = new int(2);
std::shared_ptr<int> sp0(p);
std::shared_ptr<int> sp1(p); // 錯誤, 不能將同一原始指針對象給兩個智能指針對象管理
(2) 不要把 this 指針給智能指針對象, 對所有的智能指針對象(包括 auto_ptr)都成立, 下面的代碼演示錯誤的使用方法
#define PRINT_FUN() printf("%s:%d\n", __FUNCTION__, __LINE__) class CTest{ public: CTest(){}; ~CTest(){ PRINT_FUN(); }; void Run() { m_sp = std::shared_ptr<CTest>(this); // 錯誤, 當 CTest 對象釋放時也會釋放 m_sp , 此時會再次 delete CTest 對象. (析構函數中的打印消息可以看出會出現一個對象兩次調用析構函數.) } private: std::shared_ptr<CTest> m_sp; }; std::shared_ptr<CTest> sp(new CTest()); sp->Run(); 或者這樣寫 CTest t; t.Run();
(3) 不要在函數實參裡創建智能指針對象
function ( shared_ptr<int>(new int), g( ) ); //有缺陷
可能的過程是先 new int, 然後調 g( ), g( )發生異常, shared_ptr<int> 沒有創建, int內存洩露
推薦寫法:
shared_ptr<int> p(new int());
f(p, g());
(4) 處理不是 new 創建的對象要小心. 如果確實需要這樣做, 需要智能指針傳遞一個刪除器, 自定義刪除行為.
int* pi = (int*) malloc(4);
shared_ptr<int> sp(pi); // shared_ptr 析構時將調用 delete. 使用 malloc 分配內存, 用 delete 釋放顯然不對.
(5) 不要使用 new 創建一個智能指針對象.如 new shared_ptr<T> : 本來 shared_ptr 就是為了管理指針資源的, 不要又引入一個需要管理的指針資源shared_ptr<T>*
(6) 使用 dynamic_pointer_cast 進行轉換(C++11 中已廢棄 shared_dynamic_cast)
class B { public: B(){}; virtual ~B(){}; }; class D : public B { public: D(){}; virtual ~D(){}; }; std::shared_ptr<B> sp(new D); B* b = sp.get(); D* d = dynamic_cast<D*>(b); 正確用法: std::shared_ptr<B> spb(new D); std::shared_ptr<D> spd = std::dynamic_pointer_cast<D>(spb);
(7) 不要 memcpy 智能指針對象
shared_ptr<B> sp1(new B);
shared_ptr<B> sp2;
memcpy(&sp2, &sp1, sizeof(shared_ptr<B>)); //sp2.use_count()==1
很顯然,不是通過正常途徑(拷貝構造,賦值運算),引用計數是不會正確增長的。
(8) 智能指針對象數組的使用, 需要自定義釋放器.
shared_ptr 數組, std::shared_ptr<A> p(new A[10], std::default_delete<A[]>());
std::unique_ptr<int[]>(new int[10], std::default_delete<int[]>());
(9) 將智能指針對象作為函數參數傳遞時要小心, 如下面的代碼, 當調用所在的表達式結束(即函數調用返回)時, 這個臨時對象就被銷毀了, 它所指向的內存也被釋放.
int* pa = new int(10); // 小心, 不是一個智能指針
f(std::shared_ptr<int>(pa)); // 合法的, 但內存會被釋放
int a = *pa; // 錯誤, pa已經被釋放, 但繼續指向已經釋放的內存, 從而變成了一個空懸指針, 現在試圖訪問 pa 的值, 其結果是未定義的
應該這樣使用:
std::shared_ptr<int> sp(new int(10));
f(std::shared_ptr<int>(sp)); // 調用拷貝構造函數, sp.use_count == 2
(10) 當將一個智能指針對象(如 shared_ptr)綁定到一個普通指針時, 就將內存管理的責任交給了這個 shared_ptr. 此後就不應該使用內置指針來訪問 shared_ptr 所指向的內存了.
(11) 不能使用 delete 釋放 get 返回的普通指針. get 函數的設計是為了向不能使用智能指針的代碼傳遞一個普通指針, 應該減少 get 函數的調用.
(12) 不要使用 get 返回的普通指針來初始化另一個智能指針, 或為另一個智能指針賦值. 顯然如果這樣做, 將導致兩次釋放相同的內存, 或者其中一個已經將內存釋放, 但另一個還在使用.
std::shared_ptr<int> sp = std::make_shared<int>(10);
int* p = sp.get();
{
std::shared_ptr<int> sp(p);
}
int x = *sp;