shared_ptr

shared_ptr

shared_ptr是一種智能指針(smart pointer),作用有如同指針,但會記錄有多少個shared_ptrs共同指向一個對象。這便是所謂的引用計數(reference counting)。

一旦最後一個這樣的指針被銷毀,也就是一旦某個對象的引用計數變為0,這個對象會被自動刪除。這在非環形數據結構中防止資源泄露很有幫助。

作用


auto_ptr由於它的破壞性複製語義,無法滿足標準容器對元素的要求,因而不能放在標準容器中;如果我們希望當容器析構時能自動把它容納的指針元素所指的對象刪除時,通常採用一些間接的方式來實現,顯得比較繁瑣。boost庫中提供了一種新型的智能指針shared_ptr,它解決了在多個指針間共享對象所有權的問題,同時也滿足容器對元素的要求,因而可以安全地放入容器中。

歷史


shared_ptr最初實現於Boost庫中,後來被C++標準委員會收錄於TR1技術報告中,成為C++11標準的一部分。

概要


namespace boost {
class bad_weak_ptr: public std::exception;
template class weak_ptr;
template class shared_ptr {
public:
typedef T element_type;
shared_ptr(); // never throws
template explicit shared_ptr(Y * p);
template shared_ptr(Y * p, D d);
template shared_ptr(Y * p, D d, A a);
~shared_ptr(); // never throws
shared_ptr( shared_ptr(shared_ptr const & r); // never throws
template shared_ptr(shared_ptr const & r, T * p); // never throws
template explicit shared_ptr(weak_ptr const & r);
template explicit shared_ptr(std::auto_ptr & r);
shared_ptr & operator=( shared_ptr & operator=(shared_ptr const & r); // never throws
template shared_ptr & operator=(std::auto_ptr & r);
void reset(); // never throws
template void reset(Y * p);
template void reset(Y * p, D d);
template void reset(Y * p, D d, A a);
template void reset(shared_ptr const & r, T * p); // never throws
T & operator*() const; // never throws
T * operator->() const; // never throws
T * get() const; // never throws
bool unique() const; // never throws
long use_count() const; // never throws
operatorunspecified-bool-type() const; // never throws
void swap(shared_ptr & b); // never throws
};
template
bool operator==(shared_ptr const & a, shared_ptr const & b); // never throws
template
bool operator!=(shared_ptr const & a, shared_ptr const & b); // never throws
template
bool operator<(shared_ptr const & a, shared_ptr const & b); // never throws
template void swap(shared_ptr & a, shared_ptr & b); // never throws
template T * get_pointer(shared_ptr const & p); // never throws
template
shared_ptr static_pointer_cast(shared_ptr const & r); // never throws
template
shared_ptr const_pointer_cast(shared_ptr const & r); // never throws
template
shared_ptr dynamic_pointer_cast(shared_ptr const & r); // never throws
template
std::basic_ostream & operator<<(std::basic_ostream & os, shared_ptr const & p);
template
D * get_deleter(shared_ptr const & p);
}

用法


刪除共享對象

使用shared_ptr解決的主要問題是知道刪除一個被多個客戶共享的資源的正確時機。下面是一個簡單易懂的例子,有兩個類 A和 B, 它們共享一個int實例。使用 boost::shared_ptr, 你必須包含"boost/shared_ptr.hpp".
類 A和 B都保存了一個 shared_ptr. 在創建 A和 B的實例時,shared_ptr temp被傳送到它們的構造函數。這意味著共有三個 shared_ptr:a, b, 和 temp,它們都引向同一個int實例。如果我們用指針來實現對一個的共享,A和 B必須能夠在某個時間指出這個int要被刪除。在這個例子中,直到main的結束,引用計數為3,當所有 shared_ptr離開了作用域,計數將達到0,而最後一個智能指針將負責刪除共享的 int.

標準容器

把對象直接存入容器中有時會有些麻煩。以值的方式保存對象意味著使用者將獲得容器中的元素的拷貝,對於那些複製是一種昂貴的操作的類型來說可能會有性能的問題。此外,有些容器,特別是 std::vector, 當你加入元素時可能會複製所有元素,這更加重了性能的問題。最後,傳值的語義意味著沒有多態的行為。如果你需要在容器中存放多態的對象而且你不想切割它們,你必須用指針。如果你用裸指針,維護元素的完整性會非常複雜。從容器中刪除元素時,你必須知道容器的使用者是否還在引用那些要刪除的元素,不用擔心多個使用者使用同一個元素。這些問題都可以用shared_ptr來解決。
下面是如何把共享指針存入標準庫容器的例子。