ImageVerifierCode 换一换
格式:DOCX , 页数:25 ,大小:26.08KB ,
资源ID:9402068      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/9402068.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(C++智能指针.docx)为本站会员(b****7)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

C++智能指针.docx

1、C+智能指针【C+】智能指针类和OpenCV的Ptr模板类2015-03-29 21:18智能指针类引用计数智能指针(smart pointer)的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象的指针指向同一对象。引用计数为0时,删除对象。其基本使用规则是:每次创建类的新对象时,初始化指针并将引用计数置为1。当对象作为另一对象的副本而创建时,复制构造函数复制指针并增加与之相应的引用计数的值。对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数的值(如果引用计数减至0,则删除对象),并增加右操作

2、数所指对象的引用计数的值。最后,调用析构函数时,析构函数减少引用计数的值,如果计数减至0,则删除基础对象。实现引用计数有两种经典策略:一是引入辅助类(包含引用计数型),二是使用句柄类(分离引用计数型)。策略1:引用计数类这个类的所有成员均为 private。我们不希望用户使用 U_Ptr 类,所以它没有任何 public 成员。将 HasPtr 类设置为友元, 使其成员可以访问 U_Ptr 的成员。U_Ptr 类保存指针和使用计数,每个 HasPtr 对象将指向一个 U_Ptr 对象,使用计数将跟踪指向每个U_Ptr 对象的 HasPtr 对象的数目。U_Ptr 定义的仅有函数是构造函数和析构

3、函数,构造函数复制指针,而析构函数删除它。构造函数还将使用计数置为 1,表示一个 HasPtr 对象指向这个 U_Ptr 对象。class U_Ptr friend class HasPtr; int *ip; int use; U_Ptr(int *p):ip(p) U_Ptr() delete ip; ;class HasPtrpublic: HasPtr(int *p, int i):_ptr(new U_Ptr(p),_val(i) HasPtr(const HasPtr& obj):_ptr(obj._ptr),_val(obj._val) +_ptr-use; HasPtr& op

4、erator=(const HasPtr&); 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

5、 对象,该 U_Ptr 对象的使用计数加1。析构函数将检查 U_Ptr 基础对象的使用计数。如果使用计数为 0,则这是最后一个指向该 U_Ptr 对象的 HasPtr 对象,在这种情况下,HasPtr 析构函数删除其 U_Ptr 指针。删除该指针将引起对 U_Ptr 析构函数的调用,U_Ptr 析构函数删除 int 基础对象。赋值与引用计数首先将右操作数中的使用计数加 1,然后将左操作数对象的使用计数减 1 并检查这个使用计数。像析构函数中那样,如果这是指向 U_Ptr 对象的最后一个对象,就删除该对象,这会依次撤销 int 基础对象。将左操作数中的当前值减 1(可能撤销该对象)之后,再将指针

6、从 rhs 复制到这个对象。赋值照常返回对这个对象的引用。HasPtr& HasPtr:operator=(const HasPtr &rhs) +rhs.ptr-use; / increment use count on rhs first if (-ptr-use = 0) delete ptr; / if use count goes to 0 on this object,delete it ptr = rhs.ptr; / copy the U_Ptr object val = rhs.val; / copy the int member return *this;这个赋值操作符在减

7、少左操作数的使用计数之前使 rhs 的使用计数加 1,从而防止自身赋值。如果左右操作数相同,赋值操作符的效果将是 U_Ptr 基础对象的使用计数加 1 之后立即减 1。值型类复制值型对象时,会得到一个不同的新副本。对副本所做的改变不会反映在原有对象上, 反之亦然。string类是值型类的一个例子。要使指针成员表现得像一个值,复制 HasPtr 对象时必须复制指针所指向的对象:复制构造函数不再复制指针,它将分配一个新的 int 对象,并初始化该对象以保存与被复制对象相同的值。每个对象都保存属于自己的 int 值的不同副本。因为每个对象保存自己的副本,所以析构函数将无条件删除指针。赋值操作符不需要

8、分配新对象,它只是必须记得给其指针所指向的对象赋新值,而不是给指针本身赋值。/复制构造函数定义HasPtr(const HasPtr &orig):ptr(new int (*orig.ptr), val(orig.val) /赋值函数定义HasPtr& HasPtr:operator=(const HasPtr &rhs) *ptr = *rhs.ptr; / copy the value pointed to val = rhs.val; / copy the int return *this;策略2:句柄类C+ 中一个通用的技术是定义包装(cover)类或句柄类。句柄类存储和管理基类指针

9、。指针所指对象的类型可以变化,它既可以指向基类类型对象又可以指向派生类型对象。用户通过句柄类访问继承层次的操作。因为句柄类使用指针执行操作,虚成员的行为将在运行时根据句柄实际绑定的对象的类型而变化。因此,句柄的用户可以获得动态行为但无须操心指针的管理。包装了继承层次的句柄有两个重要的设计考虑因素:* 像对任何保存指针的类一样,必须确定对复制控制做些什么。包装了集成层次的句柄通常表现得像一个智能指针或者像一个值。* 句柄类决定句柄接口屏蔽还是不屏蔽继承层次,如果不屏蔽继承层次,用户必须了解和使用基本层次中的对象。智能指针就是模拟指针动作的类。所有的智能指针都会重载 - 和 * 操作符。class

10、 Smart_Pointerpublic: /default constructor: unbound handle Smart_Pointer():_p(0),_use(new std:size_t(1) /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)+

11、*use; Smart_Pointer() decr_use(); Smart_Pointer& operator=(const Smart_Pointer&); /member access operators const Base *operator-() const if(_p) return _p; else throw std:logic_error(unbound Base); const Base &operator*() const if(_p) return *p; else throw std:logic_error(unbound Base); private: Base

12、 *_p; std:size_t *_use; void decr_use() if(-*use = 0) delete _p; delete _use; ;OpenCV的Ptr模板类OpenCV中的智能指针Ptr模板类就是采用分离引用计数型的句柄类实现技术。以OpenCV的人脸识别为例,实现了人脸识别中的三种算法: Eigenface、FisherFace和基于LBP特征的算法 。这三种算法也分别封装成三个类: Eigenfaces、Fisherfaces、LBPH 类,这三个类均派生自FaceRecognizer类,而 FaceRecognizer类则派生自 Algorithm 类。 Fa

13、ceRecognizer类是一个抽象基类。OpenCV就是采用一个泛型句柄类Ptr管理FaceRecognizer类的对象。template class CV_EXPORTS Ptr public: /! empty constructor Ptr(); /! take ownership of the pointer. The associated reference counter is allocated and set to 1 Ptr(_Tp* _obj); /! calls release() Ptr(); /! copy constructor. Copies the membe

14、rs and calls addref() Ptr(const Ptr& ptr); template Ptr(const Ptr& ptr); /! copy operator. Calls ptr.addref() and release() before copying the members Ptr& operator = (const Ptr& ptr); /! increments the reference counter void addref(); /! decrements the reference counter. If it reaches 0, delete_obj

15、() is called void release(); /! deletes the object. Override if needed void delete_obj(); /! returns true iff obj=NULL bool empty() const; /! cast pointer to another type template Ptr ptr(); template const Ptr ptr() const; /! helper operators making Ptr ptr use very similar to T* ptr. _Tp* operator

16、- (); const _Tp* operator - () const; operator _Tp* (); operator const _Tp*() const; _Tp* obj; / the object pointer. int* refcount; / the associated reference counter;当创建一个 FaceRecognizer的派生类 Eigenfaces 的对象时 , 我们把这个 Eigenfaces对象 放进 Ptr对象 内,就可以依赖句柄类 Ptr 确保 Eigenfaces对象自动被释放。Ptr model = createEigenFac

17、eRecognizer(num_components, threshold);当利用 createEigenFaceRecognizer 动态创建一个 Eigenfaces 的对象后,立即把它放进 Ptr 中进行管理。获得资源后立即放进管理对象,管理对象运用析构函数确保资源被释放。Ptr createEigenFaceRecognizer(int num_components, double threshold) return new Eigenfaces(num_components, threshold);我们注意到在createEigenFaceRecognizer实现源码中,返回了动态

18、地创建Eigenfaces对象,并且隐式的转换成Ptr。由C+的泛型句柄类思考OpenCV的Ptr模板类时间2013-03-24 22:44:00博客园-原创精华区原文主题OpenCVC+泛型OpenCV(计算机视觉库)2.4.4版本已经发布了,OpenCV发展到现在,由最初的C接口变成现在的C+接口,让开发者写程序越来越简单,接口越来越合理,也不用担心内存释放问题。但要理解内部的一些实现机制,还真要费点功夫,这对开发者的C+基础要求越来越高。本文就是笔者在做项目过程中的一点感悟,由C+泛型句柄类思考OpenCV的Ptr模板类的实现。1、C+泛型句柄类我们知道在包含指针成员的类中,需要特别注意

19、类的复制控制,因为复制指针时只复制指针中的地址,而不会复制指针指向的对象。这将导致当两个指针同时指向同一对象时,很可能一个指针删除了一对象,另一指针的用户还认为基础对象仍然存在,此时就出现了悬垂指针。当类中有指针成员时,一般有两种方式来管理指针成员:一是采用值型的方式管理,每个类对象都保留一份指针指向的对象的拷贝;另一种更好的方式是使用智能指针,从而实现指针指向的对象的共享。(可参看C+ Primer第四版P419)智能指针(smart pointer)的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共

20、享同一指针。每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的父本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,析构函数减少引用计数(如果引用计数减至0,则删除基础对象)。智能指针实现引用计数有两种经典策略:一是引入辅助类(包含引用计数型),二是使用句柄类(分离引用计数型)。 辅助类的解决方案是,定义一个单独的具体类来封装指针和相应的引用计数。可参考我之前写的一个博客:辅助类实现智能指针代码如下,参考C+沉思录,利

21、用UPoint类作为辅助类封装了指针Point*和引用计数,从而代替指针Point*。这个技术的主要思想是当多个Handle类的对象在堆上共享同一个Point*指向的内存区时,我们在这个内存区上多分配一点空间存放引用计数,那么我们就可以知道有多少个Handle类的对象在共享Point*指向的内存区,当引用计数为0时,我们就可以很放心的释放掉这块内存区,而不会出现悬垂指针了。 1 /辅助类UPoint 2 class UPoint 3 private: 4 friend class Handle; 5 int u; 6 Point p; 7 UPoint(const Point& pp):u(1

22、),p(pp) 8 9 10 11 UPoint(int xx,int yy):p(xx,yy),u(1) 12 13 14 15 UPoint():u(1) 16 17 18 19 ; 20 21 class Handle 22 public: 23 Handle():up(new UPoint) 24 25 26 27 Handle(int x,int y):up(new UPoint(x,y) 28 29 30 31 Handle(const Point& up):up(new UPoint(up)32 33 34 35 /复制构造函数36 Handle(const Handle& ot

23、her):up(other.up) 37 38 +up-u; 39 40 /赋值操作符41 Handle& operator=(const Handle& other) 42 43 +other.up-u; 44 if(-up-u=0) 45 delete up; 46 47 up = other.up; 48 return *this; 49 50 Handle() 51 52 if(-up-u = 0) 53 delete up; 54 55 56 private: 57 UPoint *up; 58 ;基于辅助类的智能指针实现方式需要创建一个依赖于Point类的新类,这样做对于特定的类而

24、言是很好,但却让我们很难将句柄绑定到Point类派生的新类对象上。因此,就有了分离引用计数型的句柄类实现了。可参看C+ 沉思录P69页,OpenCV中的智能指针模板类Ptr就是基于这种计数实现。下面是采用模板的方式实现的一个泛型句柄类(分离引用计数型),参考C+ Primer第四版P561。从下面可以看出辅助类消失了,在这个句柄类中,我们用指向类型T的指针(共享对象,类似于上面的Point类型)和指向一个int的指针表示引用计数。使用T*很重要,因为正是T*使我们不仅能够将一个Handle绑定到一个T类型的对象,还能将其绑定到一个继承自T的类的对象。这个类模板的数据成员有两个:指向某个实际需要

25、管理的类型的数据的指针以及它的引用计数。它定义了复制构造函数、赋值操作符以及解引、成员访问操作符。其中解引操作符返回的是实际需要管理的数据,而箭头操作符返回的是这个指针。这两个操作符使得我们操作Handle的对象就跟操作T的对象一样。 1 #ifndef HANDLE_H 2 #define HANDLE_H 3 4 template class Handle 5 6 public: 7 /构造函数:空指针 8 Handle(T *p = 0):ptr(p),use(new size_t(1) 9 /重载解引和箭头操作符10 T& operator*();11 T* operator-();1

26、2 const T& operator*()const;13 const T* operator-()const;14 /复制构造函数15 Handle(const Handle& h):ptr(h.ptr),use(h.use)+*use;16 /重载赋值操作符17 Handle& operator=(const Handle&);18 /析构函数19 Handle()rem_ref();20 private:21 /共享的对象22 T *ptr;23 /引用计数24 size_t *use;25 /删除指针的具体函数26 void rem_ref()27 28 if(-*use = 0)2

27、9 30 delete ptr;31 delete use;32 33 34 ;35 36 template37 inline Handle& Handle:operator=(const Handle &rhs)38 39 /右操作数引用计数+140 +*rhs.use;41 /删除左操作数42 rem_ref();43 /具体对象的赋值44 ptr = rhs.ptr;45 use = rhs.use;46 return *this;47 48 49 template inline T& Handle:operator*()50 51 if(ptr)52 return *ptr;53 /空

28、指针时抛出异常54 throw std:runtime_error(dereference of unbound Handle);55 56 57 template inline T* Handle:operator-()58 59 if(ptr)60 return ptr;61 /空指针时抛出异常62 throw std:runtime_error(access through unbound Handle);63 64 65 template inline const T& Handle:operator*()const66 67 if(ptr)68 return *ptr;69 throw std:runtime_error(dereference of unbound Handle);70 71 72 template inlin

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

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