原始指針:通過new建立的*指針
智能指針:通過智能指針關鍵字(unique_ptr, shared_ptr ,weak_ptr)建立的指針
在現代 C++ 編程中,標准庫包含智能指針,該指針用於確保程序不存在內存和資源泄漏且是異常安全的。 在現代 C++ 中,原始指針僅用於范圍有限的小代碼塊、循環或者性能至關重要且不會混淆所有權的 Helper 函數中。

1 void UseRawPointer() 2 { 3 // Using a raw pointer -- not recommended. 4 Song* pSong = new Song(L"Nothing on You", L"Bruno Mars"); 5 6 // Use pSong... 7 8 // Don't forget to delete! 9 delete pSong; 10 } 11 12 13 void UseSmartPointer() 14 { 15 // Declare a smart pointer on stack and pass it the raw pointer. 16 unique_ptr<Song> song2(new Song(L"Nothing on You", L"Bruno Mars")); 17 18 // Use song2... 19 wstring s = song2->duration_; 20 //... 21 22 } // song2 is deleted automatically here.
C++ 智能指針思路類似於在語言(如 C#)中創建對象的過程:創建對象后讓系統負責在正確的時間將其刪除。 不同之處在於,單獨的垃圾回收器不在后台運行;按照標准 C++ 范圍規則對內存進行管理,以使運行時環境更快速更有效。
Notice:請始終在單獨的代碼行上創建智能指針,而絕不在參數列表中創建智能指針,這樣就不會由於某些參數列表分配規則而發生輕微泄露資源的情況。
智能指針的設計原則是在內存和性能上盡可能高效。 例如,unique_ptr 中的唯一數據成員是封裝的指針。 這意味着,unique_ptr 與該指針的大小完全相同,不是四個字節就是八個字節。 使用重載了 * 和 -> 運算符的智能指針訪問封裝指針的速度不會明顯慢於直接訪問原始指針的速度。
智能指針具有通過使用“點”表示法訪問的成員函數。 例如,一些 STL 智能指針具有釋放指針所有權的重置成員函數。 如果你想要在智能指針超出范圍之前釋放其內存將很有用,這會很有用,如以下示例所示:
void SmartPointerDemo2() { // Create the object and pass it to a smart pointer std::unique_ptr<LargeObject> pLarge(new LargeObject()); //Call a method on the object pLarge->DoSomething(); // Free the memory before we exit function block. pLarge.reset(); // Do some other work... }
智能指針通常提供直接訪問其原始指針的方法。 STL 智能指針擁有一個用於此目的的 get 成員函數,CComPtr 擁有一個公共的 p 類成員。 通過提供對基礎指針的直接訪問,你可以使用智能指針管理你自己的代碼中的內存,還能將原始指針傳遞給不支持智能指針的代碼。
void SmartPointerDemo4() { // Create the object and pass it to a smart pointer std::unique_ptr<LargeObject> pLarge(new LargeObject()); //Call a method on the object pLarge->DoSomething(); // Pass raw pointer to a legacy API LegacyLargeObjectFunction(pLarge.get()); }
C++ 標准庫智能指針
使用這些智能指針作為將指針封裝為純舊 C++ 對象 (POCO) 的首選項。
-
unique_ptr
只允許基礎指針的一個所有者。 除非你確信需要 shared_ptr,否則請將該指針用作 POCO 的默認選項。 可以移到新所有者,但不會復制或共享。 替換已棄用的auto_ptr。 與 boost::scoped_ptr 比較。 unique_ptr 小巧高效;大小等同於一個指針且支持 rvalue 引用,從而可實現快速插入和對 STL 集合的檢索。 頭文件:<memory>。 有關更多信息,請參見如何:創建和使用 unique_ptr 實例和unique_ptr 類。 -
shared_ptr
采用引用計數的智能指針。 如果你想要將一個原始指針分配給多個所有者(例如,從容器返回了指針副本又想保留原始指針時),請使用該指針。 直至所有shared_ptr 所有者超出了范圍或放棄所有權,才會刪除原始指針。 大小為兩個指針;一個用於對象,另一個用於包含引用計數的共享控制塊。 頭文件:<memory>。 有關更多信息,請參見如何:創建和使用 shared_ptr 實例和shared_ptr 類。 -
weak_ptr
結合 shared_ptr 使用的特例智能指針。 weak_ptr 提供對一個或多個 shared_ptr 實例擁有的對象的訪問,但不參與引用計數。 如果你想要觀察某個對象但不需要其保持活動狀態,請使用該實例。 在某些情況下,需要斷開 shared_ptr 實例間的循環引用。 頭文件:<memory>。 有關更多信息,請參見如何:創建和使用共享 weak_ptr 實例和weak_ptr 類。


void SongVector() { vector<unique_ptr<Song>> v; // Create a few new unique_ptr<Song> instances // and add them to vector using implicit move semantics. v.push_back(unique_ptr<Song>(new Song(L"B'z", L"Juice"))); v.push_back(unique_ptr<Song>(new Song(L"Namie Amuro", L"Funky Town"))); v.push_back(unique_ptr<Song>(new Song(L"Kome Kome Club", L"Kimi ga Iru Dake de"))); v.push_back(unique_ptr<Song>(new Song(L"Ayumi Hamasaki", L"Poker Face"))); // Pass by reference to lambda body. for_each(v.begin(), v.end(), [] (const unique_ptr<Song>& p) { wcout << L"Artist: " << p->artist << L"Title: " << p->title << endl; }); }

class MyClass { private: // MyClass owns the unique_ptr. unique_ptr<ClassFactory> factory; public: // Initialize by invoking the unique_ptr move constructor. MyClass() : factory ( unique_ptr<ClassFactory>(new ClassFactory())) { } void MakeClass() { factory->DoSomething(); } };