什麼是智能指針,什麼時候應使用? html
http://en.wikipedia.org/wiki/Smart_pointer 程序員
在計算機科學中,智能指針是一種抽象數據類型,它在提供其餘功能(例如自動垃圾收集或邊界檢查)的同時模擬指針。 這些附加功能旨在減小因濫用指針而致使的錯誤,同時保持效率。 智能指針一般會跟蹤指向它們的對象,以進行內存管理。 指針的濫用是錯誤的主要來源:必須由使用指針編寫的程序執行常量分配,釋放和引用,這極可能會發生一些內存泄漏。 智能指針試圖經過使資源自動分配來防止內存泄漏:當指向某個對象的指針(或一系列指針中的最後一個)被破壞時,例如,因爲超出範圍,指向的對象也將被破壞。 安全
智能指針就像常規的(類型化的)指針同樣,如「 char *」,除了當指針自己超出範圍時,它所指向的內容也會被刪除。 您能夠像使用常規指針同樣使用「->」來使用它,可是若是您須要一個實際的數據指針,則不須要。 爲此,您可使用「&* ptr」。 併發
它對: app
必須分配給new的對象,但您但願擁有與該堆棧上的對象相同的生存期。 若是將對象分配給智能指針,則在程序退出該功能/塊時將刪除它們。 函數
類的數據成員,以便在刪除對象時也刪除全部擁有的數據,而在析構函數中沒有任何特殊代碼(您須要確保析構函數是虛擬的,這幾乎老是一件好事) 。 ui
你可能不但願使用智能指針時: spa
也能夠看看: 指針
大多數類型的智能指針都會爲您處理指向對象的處理。 這很是方便,由於您沒必要再考慮手動處理對象。 code
最經常使用的智能指針是std::tr1::shared_ptr
(或boost::shared_ptr
),以及std::auto_ptr
。 我建議按期使用shared_ptr
。
shared_ptr
很是通用,能夠處理各類處置方案,包括須要「跨越DLL邊界傳遞對象」的狀況(若是在代碼和DLL之間使用不一樣的libc
則一般是噩夢)。
智能指針是一種相似指針的類型,具備一些其餘功能,例如自動內存釋放,引用計數等。
在智能指針-什麼,爲何,哪一個頁面上提供了小型介紹。 。
一種簡單的智能指針類型是std::auto_ptr
(C ++標準的20.4.5章),它容許在超出範圍時自動釋放內存,而且比引起異常時的簡單指針使用更可靠,儘管這種狀況較少靈活。
另外一個方便的類型是boost::shared_ptr
,它實現引用計數並在沒有剩餘對對象的引用時自動釋放內存。 這有助於避免內存泄漏,而且易於使用來實現RAII 。
David Vandevoorde的《 C ++模板:完整指南》一書在Nicolai M. Josuttis的第20章「智能指針」中進行了詳細介紹。 涵蓋了一些主題:
更新
這個答案很舊,所以描述了當時的「好」,這是Boost庫提供的智能指針。 從C ++ 11開始,標準庫提供了足夠的智能指針類型,所以您應該同意使用std::unique_ptr
, std::shared_ptr
和std::weak_ptr
。
還有std::auto_ptr
。 它很是相似於做用域指針,不一樣之處在於它還具備「特殊」危險功能,可被複制-還會意外地轉移全部權。
它在C ++ 11中已棄用,在C ++ 17中已刪除 ,所以您不該該使用它。
std::auto_ptr<MyObject> p1 (new MyObject()); std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership. // p1 gets set to empty! p2->DoSomething(); // Works. p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.
老答案
智能指針是包裝「原始」(或「裸露」)C ++指針的類,用於管理所指向對象的生命週期。 沒有單一的智能指針類型,可是它們都嘗試以一種實用的方式抽象一個原始指針。
智能指針應優於原始指針。 若是您以爲須要使用指針(首先考慮是否確實須要使用指針),則一般但願使用智能指針,由於這能夠減輕原始指針的許多問題,主要是忘記刪除對象和泄漏內存。
使用原始指針,程序員必須在再也不有用時顯式銷燬該對象。
// Need to create the object to achieve some goal MyObject* ptr = new MyObject(); ptr->DoSomething(); // Use the object in some way delete ptr; // Destroy the object. Done with it. // Wait, what if DoSomething() raises an exception...?
經過比較,智能指針定義了有關銷燬對象的時間的策略。 您仍然必須建立對象,可是沒必要擔憂銷燬它。
SomeSmartPtr<MyObject> ptr(new MyObject()); ptr->DoSomething(); // Use the object in some way. // Destruction of the object happens, depending // on the policy the smart pointer class uses. // Destruction would happen even if DoSomething() // raises an exception
使用的最簡單策略涉及智能指針包裝器對象的範圍,例如經過boost::scoped_ptr
或std::unique_ptr
。
void f() { { std::unique_ptr<MyObject> ptr(new MyObject()); ptr->DoSomethingUseful(); } // ptr goes out of scope -- // the MyObject is automatically destroyed. // ptr->Oops(); // Compile error: "ptr" not defined // since it is no longer in scope. }
請注意,沒法複製std::unique_ptr
實例。 這樣能夠防止屢次(不正確)刪除指針。 可是,您能夠將對其的引用傳遞給您調用的其餘函數。
若是要將對象的生存期綁定到特定代碼塊,或者將其做爲成員數據嵌入另外一個對象的生存std::unique_ptr
則std::unique_ptr
頗有用。 該對象將一直存在,直到退出包含代碼的塊,或者直到包含對象自己被銷燬爲止。
更復雜的智能指針策略涉及對指針進行引用計數。 這確實容許複製指針。 當該對象的最後一個「引用」被銷燬時,該對象將被刪除。 該策略由boost::shared_ptr
和std::shared_ptr
。
void f() { typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias MyObjectPtr p1; // Empty { MyObjectPtr p2(new MyObject()); // There is now one "reference" to the created object p1 = p2; // Copy the pointer. // There are now two references to the object. } // p2 is destroyed, leaving one reference to the object. } // p1 is destroyed, leaving a reference count of zero. // The object is deleted.
當對象的生存期很是複雜,而且不直接與代碼的特定部分或另外一個對象綁定時,引用計數的指針很是有用。
引用計數的指針有一個缺點-可能建立懸掛的引用:
// Create the smart pointer on the heap MyObjectPtr* pp = new MyObjectPtr(new MyObject()) // Hmm, we forgot to destroy the smart pointer, // because of that, the object is never destroyed!
另外一種可能性是建立循環引用:
struct Owner { std::shared_ptr<Owner> other; }; std::shared_ptr<Owner> p1 (new Owner()); std::shared_ptr<Owner> p2 (new Owner()); p1->other = p2; // p1 references p2 p2->other = p1; // p2 references p1 // Oops, the reference count of of p1 and p2 never goes to zero! // The objects are never destroyed!
要變通解決此問題,Boost和C ++ 11都定義了weak_ptr
來定義對shared_ptr
的弱(未計數)引用。