1. 程式人生 > >boost庫學習:智慧指標

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

 

參考:

Boost C++ 庫 第 2 章 智慧指標

從零開始學C++之boost庫(一):詳解 boost 庫智慧指標(scoped_ptr 、shared_ptr 、weak_ptr 原始碼分析) 博主總結了很多Linux C 程式設計的內容

C++學習 boost學習之-intrusive_ptr