boost庫學習:智慧指標
scoped_ptr
也叫作用域指標,一個指標獨佔一個動態分配的物件。對應的類名為 boost::scoped_ptr
,它的定義在 boost/scoped_ptr.hpp
中。
與 std::auto_ptr 區別:不能將所指物件的所有權轉移到另一個
scoped_ptr。離開定義指標的作用域後,指標所指動態物件的空間將會釋放。
原始碼
boost_1_69_0\boost\smart_ptr\scoped_ptr.hpp
主要有reset 和 swap 方法
簡單使用
#include <iostream> #include <boost/scoped_ptr.hpp> using namespace std; class A { public: A(const int num) : val(num) {} ~A() { cout << "A destroy" << endl; } int val; }; int main() { boost::scoped_ptr<A> ptr1(new A(10)); boost::scoped_ptr<A> ptr2(new A(5)); cout << ptr1->val <<endl; cout << ptr2->val <<endl; // swap ptr1.swap(ptr2); cout << ptr1->val <<endl; cout << ptr2->val <<endl; //ptr1 = ptr2; // 編譯不過 //ptr1.reset(ptr1.get()); // 執行出錯 Assertion `p == 0 || p != px' //ptr1.reset(ptr2.get()); // 輸出三個 "A destroy"(原因參見reset實現) 但是此時ptr1 和 ptr2 指向相同的地址,釋放兩次導致出錯 ptr1.reset(new A(11)); // 執行成功,輸出三個 "A destroy" return 0; }
scoped_array
作用域陣列,與scoped_ptr 相似。 不同在於,作用域陣列的解構函式使用 delete[]
操作符來釋放所包含的物件,所以針對的是叢臺分配的陣列物件。
原始碼
boost_1_69_0\boost\smart_ptr\scoped_array.hpp
簡單使用
#include <iostream> #include <boost/scoped_array.hpp> using namespace std; class A { public: A() : val(0) {} ~A() { cout << "A destroy" << endl; } int val; }; int main() { boost::scoped_array<A> ptr1(new A[2]); ptr1[0].val = 1; (ptr1.get() + 1)->val = 2; //(ptr1.get() + 5)->val = 2; // 貌似不會報錯 for (int i = 0; i < 2; i ++) { cout << (ptr1.get() + i)->val <<endl; } return 0; }
shared_ptr
共享指標
基本與scoped_ptr 相同,不同在於不需獨佔一個物件,可以與其他shared_ptr 共同指向同一個物件,只有最後一個指向該物件的shared_ptr 銷燬後,物件的空間才會被釋放。
原始碼
boost_1_69_0\boost\smart_ptr\shared_ptr.hpp
簡單使用
#include <iostream> #include <boost/shared_ptr.hpp> using namespace std; class A { public: A(const int num) : val(num) {} ~A() { cout << "A destroy" << endl; } int val; }; int main() { boost::shared_ptr<A> ptr1(new A(5)); boost::shared_ptr<A> ptr2(ptr1); cout << ptr1->val << endl; cout << ptr2->val << endl; ptr2.reset(new A(3)); cout << ptr1->val << endl; cout << ptr2->val << endl; return 0; }
輸出:
5
5
5
3
A destroy
A destroy
shared_array
共享陣列
類似於共享指標。 不同在於析構時預設使用 delete[]
操作符來釋放所含的物件,相當於 scoped_array 和scoped_ptr的關係
原始碼
shared_array.hpp
簡單使用
#include <iostream>
#include <boost/shared_array.hpp>
using namespace std;
class A
{
public:
A() : val(0) {}
~A()
{
cout << "A destroy" << endl;
}
int val;
};
int main()
{
boost::shared_array<A> ptr1(new A[2]);
boost::shared_array<A> ptr2(new A[3]);
ptr1.get()->val = 1;
ptr2[0].val = 2;
ptr1.swap(ptr2);
cout << ptr1[0].val << endl;
cout << ptr2[0].val << endl;
return 0;
}
輸出:
2
1
A destroy
A destroy
A destroy
A destroy
A destroy
弱指標
不能獨立使用,只有配合共享指標使用才有意義
weak_ptr
必須通過 shared_ptr
來初始化的。
主要方法:lock()
作用:
返回另一個 shared_ptr,
與用於初始化弱指標的shared_ptr
共享所有權。
weak_ptr
使用場景:當函式需要一個由共享指標所管理的物件,而這個物件的生存期又不依賴於這個函式時,就可以使用弱指標。
原始碼
boost/weak_ptr.hpp
簡單使用
#include <iostream>
#include <boost/weak_ptr.hpp>
#include <boost/shared_ptr.hpp>
using namespace std;
class A
{
public:
A(const int num) : val(num) {}
~A()
{
cout << "A destroy, num:" << val << endl;
}
int val;
};
int main()
{
boost::shared_ptr<A> ptr0(new A(1));
boost::weak_ptr<A> ptr1(ptr0);
//ptr0.reset(); boost::shared_ptr<A> ptr2 = ptr1.lock(); // 這樣執行順序不會輸出ptr2->val的值
boost::shared_ptr<A> ptr2 = ptr1.lock(); ptr0.reset(); // 這樣執行順序會輸出ptr2->val的值
if (ptr2)
{
cout << ptr2->val <<endl;
}
return 0;
}
以上程式碼,因為在ptr0釋放之前,先用弱指標獲得了一個共享指標,所以ptr0的reset並不會導致所指物件空間釋放;要是改成註釋掉的那句,那後面的ptr2->val 就不會輸出。因為空間已經釋放了。
介入式指標
intrusive_ptr
與shared_ptr 工作方式近似,但是共享指標自己負責記錄物件的引用次數,介入式指標需要程式設計師自己記錄。
是一個侵入式的引用計數型指標,它可以用於以下兩種情形:
1、對記憶體佔用的要求非常嚴格,要求必須與原始指標一樣;
2、現存程式碼已經有了引用計數機制管理的物件
原始碼
intrusive_ptr.hpp
簡單使用
#include <iostream>
#include <boost/intrusive_ptr.hpp>
using namespace std;
class A {
int count;
public:
A() : count(0) {}
virtual ~A()
{
cout << "A destroy" <<endl;
}
friend void intrusive_ptr_add_ref(A* p) {
++p->count;
}
friend void intrusive_ptr_release(A* p) {
if (--p->count==0)
delete p;
}
void add_ref() {
++count;
}
int release() {
return --count;
}
int getCount()
{
return count;
}
protected:
A& operator=(const A&) {
// 無操作
return *this;
}
private:
// 禁止複製建構函式
A(const A&);
};
int main(int argc, char* argv[])
{
boost::intrusive_ptr<A> ptr0(new A());
cout << ptr0->getCount() << endl;
boost::intrusive_ptr<A> ptr1(ptr0);
cout << ptr0->getCount() << endl;
return 0;
}
輸出:
1
2
A destroy
指標容器
原始碼
boost/ptr_container/ptr_vector.hpp
簡單使用
有了以上的智慧指標,將物件儲存到容器裡,可用以下寫法一:
#include <boost/shared_ptr.hpp>
#include <vector>
#include <iostream>
#include <boost/ptr_container/ptr_vector.hpp>
using namespace std;
int main()
{
// 寫法一
std::vector<boost::shared_ptr<int> > v;
v.push_back(boost::shared_ptr<int>(new int(1)));
v.push_back(boost::shared_ptr<int>(new int(2)));
cout << *v[0].get() << endl;
//寫法二
boost::ptr_vector<int> v1;
v1.push_back(new int(1));
v1.push_back(new int(2));
cout << *v[0] << endl;
}
第一種寫法有以下問題:
1、反覆宣告 boost::shared_ptr
需要更多的輸入
2、將 boost::shared_ptr
拷進、拷出,或者在容器內部做拷貝,需要頻繁的增加或者減少內部引用計數,效率不高
Boost C++ 庫提供了 指標容器 專門用來管理動態分配的物件,參考以上程式碼寫法二。
boost::ptr_vector
專門用於動態分配的物件,它使用起來更容易也更高效。 但會獨佔它所包含的物件,因而容器之外的共享指標不能共享所有權,這跟 std::vector<boost::shared_ptr<int> >
相反。
專門用於管理動態分配物件的容器還包括:boost::ptr_deque
, boost::ptr_list
, boost::ptr_set
, boost::ptr_map
, boost::ptr_unordered_set
和 boost::ptr_unordered_map
。這些容器等價於C++標準裡提供的那些。最後兩個容器對應於std::unordered_set
和 std::unordered_map
參考:
從零開始學C++之boost庫(一):詳解 boost 庫智慧指標(scoped_ptr 、shared_ptr 、weak_ptr 原始碼分析) 博主總結了很多Linux C 程式設計的內容