C++智能指针文档格式.docx

上传人:b****7 文档编号:22538123 上传时间:2023-02-04 格式:DOCX 页数:25 大小:26.08KB
下载 相关 举报
C++智能指针文档格式.docx_第1页
第1页 / 共25页
C++智能指针文档格式.docx_第2页
第2页 / 共25页
C++智能指针文档格式.docx_第3页
第3页 / 共25页
C++智能指针文档格式.docx_第4页
第4页 / 共25页
C++智能指针文档格式.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

C++智能指针文档格式.docx

《C++智能指针文档格式.docx》由会员分享,可在线阅读,更多相关《C++智能指针文档格式.docx(25页珍藏版)》请在冰豆网上搜索。

C++智能指针文档格式.docx

_ptr(obj._ptr),_val(obj._val)

++_ptr->

use;

HasPtr&

operator=(constHasPtr&

);

~HasPtr()

if(--_ptr->

use==0)

delete_ptr;

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=(constHasPtr&

rhs)

++rhs.ptr->

//incrementusecountonrhsfirst

if(--ptr->

deleteptr;

//ifusecountgoesto0onthisobject,deleteit

ptr=rhs.ptr;

//copytheU_Ptrobject

val=rhs.val;

//copytheintmember

return*this;

}

这个赋值操作符在减少左操作数的使用计数之前使rhs的使用计数加1,从而防止自身赋值。

如果左右操作数相同,赋值操作符的效果将是U_Ptr基础对象的使用计数加1之后立即减1。

值型类

复制值型对象时,会得到一个不同的新副本。

对副本所做的改变不会反映在原有对象上,反之亦然。

string类是值型类的一个例子。

要使指针成员表现得像一个值,复制HasPtr对象时必须复制指针所指向的对象:

复制构造函数不再复制指针,它将分配一个新的int对象,并初始化该对象以保存与被复制对象相同的值。

每个对象都保存属于自己的int值的不同副本。

因为每个对象保存自己的副本,所以析构函数将无条件删除指针。

赋值操作符不需要分配新对象,它只是必须记得给其指针所指向的对象赋新值,而不是给指针本身赋值。

//复制构造函数定义

HasPtr(constHasPtr&

orig):

ptr(newint(*orig.ptr)),val(orig.val){}

//赋值函数定义

*ptr=*rhs.ptr;

//copythevaluepointedto

//copytheint

策略2:

句柄类

C++中一个通用的技术是定义包装(cover)类或句柄类。

句柄类存储和管理基类指针。

指针所指对象的类型可以变化,它既可以指向基类类型对象又可以指向派生类型对象。

用户通过句柄类访问继承层次的操作。

因为句柄类使用指针执行操作,虚成员的行为将在运行时根据句柄实际绑定的对象的类型而变化。

因此,句柄的用户可以获得动态行为但无须操心指针的管理。

包装了继承层次的句柄有两个重要的设计考虑因素:

*像对任何保存指针的类一样,必须确定对复制控制做些什么。

包装了集成层次的句柄通常表现得像一个智能指针或者像一个值。

*句柄类决定句柄接口屏蔽还是不屏蔽继承层次,如果不屏蔽继承层次,用户必须了解和使用基本层次中的对象。

智能指针就是模拟指针动作的类。

所有的智能指针都会重载->

和*操作符。

classSmart_Pointer

//defaultconstructor:

unboundhandle

Smart_Pointer():

_p(0),_use(newstd:

size_t

(1)){}

//attachesahandletoacopyoftheBaseobject

Smart_Pointer(constBase&

//copycontrolmemberstomanagetheusecountandpointers

Smart_Pointer(constSmart_Pointer&

i):

_p(i._p),_use(i._use){++*use;

~Smart_Pointer(){decr_use();

Smart_Pointer&

operator=(constSmart_Pointer&

//memberaccessoperators

constBase*operator->

()const

if(_p)

return_p;

else

throwstd:

logic_error("

unboundBase"

constBase&

operator*()const

return*p;

Base*_p;

std:

size_t*_use;

voiddecr_use()

if(--*use==0)

delete_p;

delete_use;

OpenCV的Ptr模板类

OpenCV中的智能指针Ptr模板类就是采用分离引用计数型的句柄类实现技术。

以OpenCV的人脸识别为例,实现了人脸识别中的三种算法:

Eigenface、FisherFace和基于LBP特征的算法。

这三种算法也分别封装成三个类:

Eigenfaces、Fisherfaces、LBPH类,这三个类均派生自FaceRecognizer类,而FaceRecognizer类则派生自Algorithm类。

FaceRecognizer类是一个抽象基类。

OpenCV就是采用一个泛型句柄类Ptr管理FaceRecognizer类的对象。

template<

typename_Tp>

classCV_EXPORTSPtr

public:

//!

emptyconstructor

Ptr();

takeownershipofthepointer.Theassociatedreferencecounterisallocatedandsetto1

Ptr(_Tp*_obj);

callsrelease()

~Ptr();

copyconstructor.Copiesthemembersandcallsaddref()

Ptr(constPtr&

ptr);

template<

typename_Tp2>

Ptr(constPtr<

_Tp2>

&

copyoperator.Callsptr.addref()andrelease()beforecopyingthemembers

Ptr&

operator=(constPtr&

incrementsthereferencecounter

voidaddref();

decrementsthereferencecounter.Ifitreaches0,delete_obj()iscalled

voidrelease();

deletestheobject.Overrideifneeded

voiddelete_obj();

returnstrueiffobj==NULL

boolempty()const;

castpointertoanothertype

Ptr<

ptr();

constPtr<

ptr()const;

helperoperatorsmaking"

Ptr<

T>

ptr"

useverysimilarto"

T*ptr"

.

_Tp*operator->

();

const_Tp*operator->

()const;

operator_Tp*();

operatorconst_Tp*()const;

_Tp*obj;

//<

theobjectpointer.

int*refcount;

theassociatedreferencecounter

当创建一个FaceRecognizer的派生类Eigenfaces的对象时,我们把这个Eigenfaces对象放进Ptr对象内,就可以依赖句柄类Ptr确保Eigenfaces对象自动被释放。

FaceRecognizer>

model=createEigenFaceRecognizer(num_components,threshold);

当利用createEigenFaceRecognizer动态创建一个Eigenfaces的对象后,立即把它放进Ptr<

FaceRecognizer>

中进行管理。

获得资源后立即放进管理对象,管理对象运用析构函数确保资源被释放。

createEigenFaceRecognizer(intnum_components,doublethreshold)

returnnewEigenfaces(num_components,threshold);

我们注意到在createEigenFaceRecognizer实现源码中,返回了动态地创建Eigenfaces对象,并且隐式的转换成Ptr。

由C++的泛型句柄类思考OpenCV的Ptr模板类

时间 

2013-03-2422:

44:

00 

博客园-原创精华区

原文 

主题 

OpenCV 

C++ 

泛型

OpenCV(计算机视觉库)2.4.4版本已经发布了,OpenCV发展到现在,由最初的C接口变成现在的C++接口,让开发者写程序越来越简单,接口越来越合理,也不用担心内存释放问题。

但要理解内部的一些实现机制,还真要费点功夫,这对开发者的C++基础要求越来越高。

本文就是笔者在做项目过程中的一点感悟,由C++泛型句柄类思考OpenCV的Ptr模板类的实现。

1、C++泛型句柄类 

我们知道在包含指针成员的类中,需要特别注意类的复制控制,因为复制指针时只复制指针中的地址,而不会复制指针指向的对象。

这将导致当两个指针同时指向同一对象时,很可能一个指针删除了一对象,另一指针的用户还认为基础对象仍然存在,此时就出现了悬垂指针。

当类中有指针成员时,一般有两种方式来管理指针成员:

一是采用值型的方式管理 

,每个类对象都保留一份指针指向的对象的拷贝;

另一种更好的方式是 

使用智能指针 

,从而实现指针指向的对象的共享。

(可参看《C++Primer第四版》P419)

智能指针(smartpointer) 

的一种通用实现技术是使用 

引用计数(referencecount)。

智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。

每次创建类的新对象时,初始化指针并将引用计数置为1;

当对象作为另一对象的父本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;

对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;

调用析构函数时,析构函数减少引用计数(如果引用计数减至0,则删除基础对象)。

智能指针实现引用计数有两种经典策略:

一是引入 

辅助类(包含引用计数型) 

,二是使用 

句柄类(分离引用计数型) 

∙辅助类的解决方案是,定义一个单独的具体类来封装指针和相应的引用计数。

可参考我之前写的一个博客:

辅助类实现智能指针代码如下,参考《C++沉思录》,利用UPoint类作为辅助类封装了指针Point*和引用计数,从而代替指针Point*。

这个技术的主要思想是当多个Handle类的对象在堆上共享同一个Point*指向的内存区时,我们在这个内存区上多分配一点空间存放引用计数,那么我们就可以知道有多少个Handle类的对象在共享Point*指向的内存区,当引用计数为0时,我们就可以很放心的释放掉这块内存区,而不会出现悬垂指针了。

1//辅助类UPoint

2classUPoint{

3private:

4friendclassHandle;

5intu;

6Pointp;

7UPoint(constPoint&

pp):

u

(1),p(pp)

8{

9

10}

11UPoint(intxx,intyy):

p(xx,yy),u

(1)

12{

13

14}

15UPoint():

u

(1)

16{

17

18}

19};

20

21classHandle{

22public:

23Handle():

up(newUPoint)

24{

25

26}

27Handle(intx,inty):

up(newUPoint(x,y))

28{

29

30}

31Handle(constPoint&

up):

up(newUPoint(up))

32{

33

34}

35//复制构造函数

36Handle(constHandle&

other):

up(other.up)

37{

38++up->

u;

39}

40//赋值操作符

41Handle&

operator=(constHandle&

other)

42{

43++other.up->

44if(--up->

u==0){

45deleteup;

46}

47up=other.up;

48return*this;

49}

50~Handle()

51{

52if(--up->

u==0){

53deleteup;

54}

55}

56private:

57UPoint*up;

58};

基于辅助类的智能指针实现方式需要创建一个依赖于Point类的新类,这样做对于特定的类而言是很好,但却让我们很难将句柄绑定到Point类派生的新类对象上。

因此,就有了分离引用计数型的句柄类实现了。

可参看《C++沉思录》P69页,OpenCV中的智能指针模板类Ptr就是基于这种计数实现。

下面是采用模板的方式实现的一个泛型句柄类(分离引用计数型),参考《C++Primer第四版》P561。

从下面可以看出辅助类消失了, 

在这个句柄类中,我们用指向类型T的指针(共享对象,类似于上面的Point类型)和指向一个int的指针表示引用计数。

使用T*很重要,因为正是T*使我们不仅能够将一个Handle绑定到一个T类型的对象,还能将其绑定到一个继承自T的类的对象。

这个类模板的数据成员有两个:

指向某个实际需要管理的类型的数据的指针以及它的引用计数。

它定义了复制构造函数、赋值操作符以及解引、成员访问操作符。

其中解引操作符返回的是实际需要管理的数据,而箭头操作符返回的是这个指针。

这两个操作符使得我们操作Handle<

的对象就跟操作T的对象一样。

1#ifndefHANDLE_H

2#defineHANDLE_H

3

4template<

classT>

classHandle

5{

6public:

7//构造函数:

空指针

8Handle(T*p=0):

ptr(p),use(newsize_t

(1)){}

9//重载解引和箭头操作符

10T&

operator*();

11T*operator->

();

12constT&

operator*()const;

13constT*operator->

()const;

14//复制构造函数

15Handle(constHandle&

h):

ptr(h.ptr),use(h.use){++*use;

16//重载赋值操作符

17Handle&

18//析构函数

19~Handle(){rem_ref();

20private:

21//共享的对象

22T*ptr;

23//引用计数

24size_t*use;

25//删除指针的具体函数

26voidrem_ref()

27{

28if(--*use==0)

29{

30deleteptr;

31deleteuse;

32}

33}

34};

35

36template<

37inlineHandle<

Handle<

operator=(constHandle&

38{

39//右操作数引用计数+1

40++*rhs.use;

41//删除左操作数

42rem_ref();

43//具体对象的赋值

44ptr=rhs.ptr;

45use=rhs.use;

46return*this;

47}

48

49template<

inlineT&

operator*()

50{

51if(ptr)

52return*ptr;

53//空指针时抛出异常

54throwstd:

runtime_error("

dereferenceofunboundHandle"

55}

56

57template<

inlineT*Handle<

operator->

()

58{

59if(ptr)

60returnptr;

61//空指针时抛出异常

62throwstd:

accessthroughunboundHandle"

63}

64

65template<

inlineconstT&

operator*()const

66{

67if(ptr)

68return*ptr;

69throwstd:

70}

71

72template<

inlin

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 党团工作 > 入党转正申请

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1