boost::shared_ptr<int> sp(new int(10)); //一個指向整數的shared_ptrassert(sp.unique()); //如今shared_ptr是指針的惟一持有者
boost::shared_ptr<int> sp2 = sp; //第二個shared_ptr,拷貝構造函數assert(sp == sp2 && sp.use_count() == 2); //兩個shared_ptr相等,指向同一個對象,引用計數爲2
*sp2 = 100; //使用解引用操做符修改被指對象
assert(*sp == 100); //另外一個shared_ptr也同時被修改
sp.reset(); //中止shared_ptr的使用,引用計數減一
assert(!sp); //sp再也不持有任何指針(空指針)
assert(sp2.use_count() == 1); //sp2引用計數變爲1
sp.reset(new int(20)); //sp管理一個新對象assert(*sp == 20);
有兩種方式能夠將shared_ptr應用於標準容器(或者容器適配器等其餘容器)。程序員
一種用法是將容器做爲shared_ptr管理的對象,如shared_ptr<list<T> >,使容器能夠被安全地共享,用法與普通shared_ptr沒有區別,咱們再也不討論。編程
另外一種用法是將shared_ptr做爲容器的元素,如vector<shared_ptr<T> >,由於shared_ptr支持拷貝語義和比較操做,符合標準容器對元素的要求,因此能夠實如今容器中安全地容納元素的指針而不是拷貝。windows
標準容器不能容納auto_ptr,這是C++標準特別規定的(讀者永遠也不要有這種想法)。標準容器也不能容納scoped_ptr,由於scoped_ptr不能拷貝和賦值。標準容器能夠容納原始指針,但這就喪失了容器的許多好處,由於標準容器沒法自動管理類型爲指針的元素,必須編寫額外的大量代碼來保證指針最終被正確刪除,這一般很麻煩很難實現。安全
存儲shared_ptr的容器與存儲原始指針的容器功能幾乎同樣,但shared_ptr爲程序員作了指針的管理工做,能夠任意使用shared_ptr而不用擔憂資源泄漏。函數
#include <boost/make_shared.hpp>int main()
{typedef vector<shared_ptr<int> > vs; //一個持有shared_ptr的標準容器類型vs v(10); //聲明一個擁有10個元素的容器,元素被初始化爲空指針
int i = 0;
for (vs::iterator pos = v.begin(); pos != v.end(); ++pos)
{(*pos) = make_shared<int>(++i); //使用工廠函數賦值cout << *(*pos) << ", "; //輸出值}cout << endl;shared_ptr<int> p = v[9];
*p = 100;cout << *v[9] << endl;}
這段代碼須要注意的是迭代器和operator[]的用法,由於容器內存儲的是shared_ptr,咱們必須對迭代器pos使用一次解引用操做符*以得到shared_ptr,而後再對shared_ptr使用解引用操做符*才能操做真正的值。*(*pos)也能夠直接寫成**pos,但前者更清晰,後者很容易讓人迷惑。vector的operator[]用法與迭代器相似,也須要使用*獲取真正的值。this
爲何要使用enable_shared_from_this,或許你對這個類感到很迷惑,先看看下面這種狀況:spa
class MyPoint
{public:
MyPoint(){std::cout << "MyPoint" << std::endl;}
~MyPoint(){std::cout << "~MyPoint" << std::endl;}
//返回this的函數
boost::shared_ptr<MyPoint> GetPoint(){return boost::shared_ptr<MyPoint>(this); //錯誤,將返回一個新的引用計數}};int _tmain(int argc, _TCHAR* argv[]){boost::shared_ptr<MyPoint> p1(new MyPoint);
boost::shared_ptr<MyPoint> p2 = p1->GetPoint();std::cout << p1.use_count() << "," << p2.use_count() << std::endl; //輸出引用計數狀況p1.reset(); //內存將被釋放
}
咱們獲得的答案將是:線程
MyPoint
1,1
~MyPoint指針
怎麼正確的返回this呢,那麼就須要藉助enable_shared_from_this了,引入enable_shared_from_this的緣由是能夠實現返回值爲指向該類自己的shared_ptrcode
正確的寫法應該是這樣的:
class MyPoint : public boost::enable_shared_from_this<MyPoint>{public:
MyPoint(){std::cout << "MyPoint" << std::endl;}
~MyPoint(){std::cout << "~MyPoint" << std::endl;}
//返回this的函數
boost::shared_ptr<MyPoint> GetPoint(){return shared_from_this();
}};int _tmain(int argc, _TCHAR* argv[]){boost::shared_ptr<MyPoint> p1(new MyPoint);
boost::shared_ptr<MyPoint> p2 = p1->GetPoint();std::cout << p1.use_count() << "," << p2.use_count() << std::endl; //輸出引用計數狀況p1.reset(); //內存將被釋放
}
當你在使用windows API函數進行編程時,你最煩的或許就是怎麼保證申請的內核對象是否關閉,考慮一下代碼:
int *p = (int*) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(p) );//業務處理
//......
HeapFree( GetProcessHeap(), 0, p );
對象不能經過delete來刪除,而是一個釋放函數,shared_ptr可否勝任呢,答案是確定的。
int *p = (int*) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(p) );//此處使用了lambda表達式,須要vs2010或更高版本的支持
boost::shared_ptr<int> ptr(p, [](int *p){HeapFree( GetProcessHeap(), 0, p );});
下面實現一個線程類,在線程運行結束時,可以自行清理本身的內存
#include <set>#include <Windows.h>#include <boost/thread.hpp>class MySelf;
std::set< boost::shared_ptr<MySelf> > myList;boost::thread *ptrTh;class MySelf: public boost::enable_shared_from_this<MySelf>{public:
MySelf(){printf("MySelf\n");
}void StartThread()
{//啓動一個線程
ptrTh = new boost::thread(&MySelf::Run, this);}void Run()
{//線程任務函數
Sleep(5000);printf("stop thread\n");
Stop();}void Stop()
{//刪除本身
myList.erase(shared_from_this());}~MySelf(){printf("~MySelf\n");
}};void TestSharePtr()
{boost::shared_ptr<MySelf> ptr1(new MySelf);
//保存到list中
myList.insert(ptr1);ptr1->StartThread();}