Boost智慧指標——shared_ptr
boost::scoped_ptr雖然簡單易用,但它不能共享所有權的特性卻大大限制了其使用範圍,而boost::shared_ptr可以解決這一侷限。顧名思義,boost::shared_ptr是可以共享所有權的智慧指標,首先讓我們通過一個例子看看它的基本用法:
#include <string> #include <iostream> #include <boost/shared_ptr.hpp> class implementation { public: ~implementation() { std::cout <<"destroying implementation\n"; } void do_something() { std::cout << "did something\n"; } }; void test() { boost::shared_ptr<implementation> sp1(new implementation()); std::cout<<"The Sample now has "<<sp1.use_count()<<" references\n"; boost::shared_ptr<implementation> sp2 = sp1; std::cout<<"The Sample now has "<<sp2.use_count()<<" references\n"; sp1.reset(); std::cout<<"After Reset sp1. The Sample now has "<<sp2.use_count()<<" references\n"; sp2.reset(); std::cout<<"After Reset sp2.\n"; } void main() { test(); }
該程式的輸出結果如下:
The Sample now has 1 references
The Sample now has 2 references
After Reset sp1. The Sample now has 1 references
destroying implementation
After Reset sp2.
可以看到,boost::shared_ptr指標sp1和sp2同時擁有了implementation物件的訪問許可權,且當sp1和sp2都釋放對該物件的所有權時,其所管理的的物件的記憶體才被自動釋放。在共享物件的訪問許可權同時,也實現了其記憶體的自動管理。
boost::shared_ptr的記憶體管理機制:
boost::shared_ptr的管理機制其實並不複雜,就是對所管理的物件進行了引用計數,當新增一個boost::shared_ptr對該物件進行管理時,就將該物件的引用計數加一;減少一個boost::shared_ptr對該物件進行管理時,就將該物件的引用計數減一,如果該物件的引用計數為0的時候,說明沒有任何指標對其管理,才呼叫delete釋放其所佔的記憶體。
上面的那個例子可以的圖示如下:
- sp1對implementation物件進行管理,其引用計數為1
- 增加sp2對implementation物件進行管理,其引用計數增加為2
- sp1釋放對implementation物件進行管理,其引用計數變為1
- sp2釋放對implementation物件進行管理,其引用計數變為0,該物件被自動刪除
boost::shared_ptr的特點:
和前面介紹的boost::scoped_ptr相比,boost::shared_ptr可以共享物件的所有權,因此其使用範圍基本上沒有什麼限制(還是有一些需要遵循的使用規則,下文中介紹),自然也可以使用在stl的容器中。另外它還是執行緒安全的,這點在多執行緒程式中也非常重要。
boost::shared_ptr的使用規則:
boost::shared_ptr並不是絕對安全,下面幾條規則能使我們更加安全的使用boost::shared_ptr:
- 避免對shared_ptr所管理的物件的直接記憶體管理操作,以免造成該物件的重釋放
- shared_ptr並不能對迴圈引用的物件記憶體自動管理(這點是其它各種引用計數管理記憶體方式的通病)。
-
不要構造一個臨時的shared_ptr作為函式的引數。
如下列程式碼則可能導致記憶體洩漏:
voidtest()
{
foo(boost::shared_ptr<implementation>(newimplementation()),g());
}
正確的用法為:
voidtest()
{
boost::shared_ptr<implementation> sp(newimplementation());
foo(sp,g());
}