C 智慧型指標類和OpenCV的Ptr模板類

2021-06-29 10:52:58 字數 4068 閱讀 2083

智慧型指標(smart pointer)的一種通用實現技術是使用引用計數(reference count)。智慧型指標類將乙個計數器與類指向的物件相關聯,引用計數跟蹤該類有多少個物件的指標指向同一物件。引用計數為0時,刪除物件。

其基本使用規則是:

每次建立類的新物件時,初始化指標並將引用計數置為1。當物件作為另一物件的副本而建立時,複製建構函式複製指標並增加與之相應的引用計數的值。對乙個物件進行賦值時,賦值操作符減少左運算元所指物件的引用計數的值(如果引用計數減至0,則刪除物件),並增加右運算元所指物件的引用計數的值。最後,呼叫析構函式時,析構函式減少引用計數的值,如果計數減至0,則刪除基礎物件。

實現引用計數有兩種經典策略:一是引入輔助類(包含引用計數型),二是使用控制代碼類(分離引用計數型)

這個類的所有成員均為 private。我們不希望使用者使用 u_ptr 類,所以它沒有任何 public 成員。將 hasptr 類設定為友元, 使其成員可以訪問 u_ptr 的成員。

u_ptr 類儲存指標和使用計數,每個 hasptr 物件將指向乙個 u_ptr 物件,使用計數將跟蹤指向每個u_ptr 物件的 hasptr 物件的數目。u_ptr 定義的僅有函式是建構函式和析構函式,建構函式複製指標,而析構函式刪除它。建構函式還將使用計數置為 1,表示乙個 hasptr 物件指向這個 u_ptr 物件。

class u_ptr

~u_ptr()

};class hasptr

hasptr(const hasptr& obj):_ptr(obj._ptr),_val(obj._val)

hasptr& operator=(const hasptr&);

~hasptr()

private:

u_ptr* _ptr;

int _val;

};

接受乙個指標和乙個 int 值的 hasptr 建構函式使用其指標形參建立乙個新的 u_ptr 物件。hasptr 建構函式執行完畢後,hasptr 物件指向乙個新分配的 u_ptr 物件,該 u_ptr 物件儲存給定指標。新 u_ptr 中的使用計數為 1,表示只有乙個 hasptr 物件指向它。

複製建構函式從形參複製成員並增加使用計數的值。複製建構函式執行完畢後,新建立物件與原有物件指向同一 u_ptr 物件,該 u_ptr 物件的使用計數加1。

析構函式將檢查 u_ptr 基礎物件的使用計數。如果使用計數為 0,則這是最後乙個指向該 u_ptr 物件的 hasptr 物件,在這種情況下,hasptr 析構函式刪除其 u_ptr 指標。刪除該指標將引起對 u_ptr 析構函式的呼叫,u_ptr 析構函式刪除 int 基礎物件。

賦值與引用計數

首先將右運算元中的使用計數加 1,然後將左運算元物件的使用計數減 1 並檢查這個使用計數。像析構函式中那樣,如果這是指向 u_ptr 物件的最後乙個物件,就刪除該物件,這會依次撤銷 int 基礎物件。將左運算元中的當前值減 1(可能撤銷該物件)之後,再將指標從 rhs 複製到這個物件。賦值照常返回對這個物件的引用。

hasptr& hasptr::operator=(const hasptr &rhs)

這個賦值操作符在減少左運算元的使用計數之前使 rhs 的使用計數加 1,從而防止自身賦值。

如果左右運算元相同,賦值操作符的效果將是 u_ptr 基礎物件的使用計數加 1 之後立即減 1。

複製值型物件時,會得到乙個不同的新副本。對副本所做的改變不會反映在原有物件上, 反之亦然。string類是值型類的乙個例子。

要使指標成員表現得像乙個值,複製 hasptr 物件時必須複製指標所指向的物件:

複製建構函式不再複製指標,它將分配乙個新的 int 物件,並初始化該物件以儲存與被複製物件相同的值。每個物件都儲存屬於自己的 int 值的不同副本。因為每個物件儲存自己的副本,所以析構函式將無條件刪除指標。

賦值操作符不需要分配新物件,它只是必須記得給其指標所指向的物件賦新值,而不是給指標本身賦值。

//複製建構函式定義

hasptr(const hasptr &orig):

ptr(new

int (*orig.ptr)), val(orig.val)

//賦值函式定義

hasptr& hasptr::operator=(const hasptr &rhs)

c++ 中乙個通用的技術是定義包裝(cover)類或控制代碼類。控制代碼類儲存和管理基類指標。指標所指物件的型別可以變化,它既可以指向基類型別物件又可以指向派生型別物件。使用者通過控制代碼類訪問繼承層次的操作。因為控制代碼類使用指標執行操作,虛成員的行為將在執行時根據控制代碼實際繫結的物件的型別而變化。因此,控制代碼的使用者可以獲得動態行為但無須操心指標的管理。

包裝了繼承層次的控制代碼有兩個重要的設計考慮因素:

* 像對任何儲存指標的類一樣,必須確定對複製控制做些什麼。包裝了整合層次的控制代碼通常表現得像乙個智慧型指標或者像乙個值。

* 控制代碼類決定控制代碼介面遮蔽還是不遮蔽繼承層次,如果不遮蔽繼承層次,使用者必須了解和使用基本層次中的物件。

智慧型指標就是模擬指標動作的類。所有的智慧型指標都會過載 -> 和 * 操作符。

class smart_pointer

//attaches a handle to a copy of the base object

smart_pointer(const base&);

//copy control members to manage the use count and pointers

smart_pointer(const smart_pointer& i):

_p(i._p),_use(i._use)

~smart_pointer()

smart_pointer& operator=(const smart_pointer&);

//member access operators

const base *operator->() const

const base &operator*() const

private:

base *_p;

std::size_t *_use;

void decr_use()

}};

opencv中的智慧型指標ptr模板類就是採用分離引用計數型的控制代碼類實現技術。

以opencv的人臉識別為例,實現了人臉識別中的三種演算法: eigenface、fishe***ce和基於lbp特徵的演算法 。這三種演算法也分別封裝成三個類: eigenfaces、fishe***ces、lbph 類,這三個類均派生自facerecognizer類,而 facerecognizer類則派生自 algorithm 類。 facerecognizer類是乙個抽象基類。

opencv就是採用乙個泛型控制代碼類ptr管理facerecognizer類的物件。

template

class cv_exports ptr

;

當建立乙個 facerecognizer的派生類 eigenfaces 的物件時 , 我們把這個 eigenfaces物件 放進 ptr物件 內,就可以依賴控制代碼類 ptr 確保 eigenfaces物件自動被釋放。

ptrmodel = createeigenfacerecognizer(num_components, threshold);
當利用 createeigenfacerecognizer 動態建立乙個 eigenfaces 的物件後,立即把它放進 ptr < facerecognizer > 中進行管理。獲得資源後立即放進管理物件,管理物件運用析構函式確保資源被釋放。

ptrcreateeigenfacerecognizer(int num_components, double threshold)

我們注意到在createeigenfacerecognizer實現原始碼中,返回了動態地建立eigenfaces物件,並且隱式的轉換成ptr。

github部落格主頁(

csdn部落格(

C 智慧型指標模板類

三個智慧型指標模板 auto ptr unique ptr shared ptr 條件 1 標頭檔案必須包含memory,include 2 智慧型指標模板位於命名空間std,std 或using namespace std 三者的區別 1 所有權。只能有乙個智慧型指標可以擁有乙個特定的物件。aut...

c 智慧型指標

auto prt 它是 它所指向物件的擁有者 所以當自身物件被摧毀時候,該物件也將遭受摧毀,要求乙個物件只有乙個擁有者,注意 auto prt 不能使用new 來分配物件給他 include include using namespace std template void bad print au...

c 智慧型指標

很久沒寫部落格了,不知道如何表達了,哈哈.我先介紹一下深淺拷貝.class copy 此時a.ptr和b.ptr指向同乙個物件,當我們delete a.ptr時 b.ptr所指向的物件已經不存在了,要是我們引用b.ptr指向的物件也就會出問題了.深拷貝 把a.ptr所指向的物件拷貝乙份給b.ptr ...