智能指针

  1. 垫M(200,200,CV_64F);  
  2. for int  i = 0; i <M.rows; i ++)  
  3. {  
  4.       
  5.     for int  j = 0; j <M.cols; j ++)  
  6.         M.at < double >(i,j)= CV_PI;  
  7. }  
  8.   
  9. /笔记  
  10. 请注意at <>方法效率不高,因为它必须精确计算  
  11. 内存位置从像素行和列。这可能非常耗时  
  12. 当我们逐像素地处理整个图像时。第二种方法使用ptr  
  13. 函数,它返回指向特定图像行的指针。以下片段  
  14. 获取彩色图像中每个像素的像素值:  
  15. /节省处理时间的方式,用PTR函数,返回一个指向图像行的指针。  
  16. uchar R,G,B;  
  17. for  (int  i = 0; i <src2.rows; i ++)  
  18. {  
  19.     Vec3b * pixrow = src2.ptr <Vec3b>(i);  
  20.     for  (int  j = 0; j <src2.cols; j ++)  
  21.     {  
  22.         B = pixrow [j] [0];  
  23.         G = pixrow [j] [1];  
  24.         R = pixrow [j] [2];  
  25.     }  
  26. }  
  27. 笔记  
  28. 在上面的示例中,ptr用于获取指向每行中第一个像素的指针。  
  29. 使用  这个 指针,我们现在可以访问最内层循环中的每一列。  




  1. C / C ++对象的generic_type ref-counting指针类/// /  
  2.   
  3. / *! 
  4.   智能指针指向动态分配的对象。 
  5.  
  6.   这是模板指针环绕类,用于存储关联的引用计数器 
  7.   对象指针。该类与最近的C ++标准插件中的std :: smart_ptr <>类似, 
  8.   但编写时间更短)和自包含的(即在编译器或外部库中添加了任何依赖关系)。 
  9.  
  10.   基本上,您可以使用“Ptr <MyObjectType> ptr”(或更快的“const Ptr <MyObjectType>&ptr”进行只读访问) 
  11.   处处代替“MyObjectType * ptr”,其中MyObjectType是一些C结构或C ++类。 
  12.   为了使这一切工作,你需要专门Ptr <> :: delete_obj(),如: 
  13.  
  14.   \码 
  15.   template <> void Ptr <MyObjectType> :: delete_obj(){call_destructor_func(obj); } 
  16.   \ endcode 
  17.  
  18.   \注意{如果MyObjectType是一个具有析构函数的C ++类,则不需要专门化delete_obj(), 
  19.   因为默认实现调用“delete obj;”} 
  20.  
  21.   \注意{这个类的另一个好的属性是参考计数器上的操作是原子的, 
  22.   即在多线程应用程序中使用该类是安全的} 
  23. * /  
  24. 模板< typename  _Tp>  class  CV_EXPORTS Ptr  
  25. {  
  26. 公众:  
  27.     //!空的构造函数  
  28.     PTR();  
  29.     //!掌握指针的所有权。关联的引用计数器被分配并设置为1  
  30.     Ptr(_Tp * _obj);  
  31.     //!调用release()  
  32.     〜PTR();  
  33.     //!复制构造函数。复制成员并调用addref()  
  34.     Ptr(const  Ptr&ptr);  
  35.     //!复制操作员。在复制成员之前调用ptr.addref()和release()  
  36.     Ptr&operator =(const  Ptr&ptr);  
  37.     //!增加参考计数器  
  38.     void  addref();  
  39.     //!递减参考计数器。如果它达到0,则调用delete_obj()  
  40.     void  release();  
  41.     //!删除对象。如果需要覆盖  
  42.     void  delete_obj();  
  43.     //!返回true iff obj == NULL  
  44.     bool  empty()  const ;  
  45.   
  46.   
  47.     //!使“Ptr <T> ptr”的辅助操作符与“T * ptr”非常相似。  
  48.     _Tp *运算符 - >();  
  49.     const  _Tp * operator - >()  const ;  
  50.   
  51.     operator _Tp* ();  
  52.     operator const _Tp*() const;  
  53.   
  54. protected:  
  55.     _Tp* obj; //< the object pointer.  
  56.     int* refcount; //< the associated reference counter  
  57. };  

所谓的智能指针,其实就是模板参数可以是任意的c++类,但考虑到对象在使用完毕的时候需要析构,因此要求特化delete_obj()函数。

接下来看源码

[cpp]  view plain  copy
  1. template<typename _Tp> inline Ptr<_Tp>::Ptr() : obj(0), refcount(0) {}  
  2. template<typename _Tp> inline Ptr<_Tp>::Ptr(_Tp* _obj) : obj(_obj)  
  3. {  
  4.     if(obj)  
  5.     {  
  6.         refcount = (int*)fastMalloc(sizeof(*refcount));  
  7.         *refcount = 1;  
  8.     }  
  9.     else  
  10.         refcount = 0;  
  11. }  
obj显然是指向对象的指针,refcount是引用数,默认构造函数就构造了一个空对象,带参数的构造函数则需要动态分配内存,当然如果参数传入NULL的话,就与默认构造函数没有区别了...注意这里使用了fastMalloc这个函数,使用了对齐指针的技术...
[cpp]  view plain  copy
  1. void* fastMalloc( size_t size )  
  2. {  
  3.     uchar* udata = (uchar*)malloc(size + sizeof(void*) + CV_MALLOC_ALIGN);  
  4.     if(!udata)  
  5.         return OutOfMemoryError(size);  
  6.     uchar** adata = alignPtr((uchar**)udata + 1, CV_MALLOC_ALIGN);  
  7.     adata[-1] = udata;  
  8.     return adata;  
  9. }  
  10.       
  11. void fastFree(void* ptr)  
  12. {  
  13.     if(ptr)  
  14.     {  
  15.         uchar* udata = ((uchar**)ptr)[-1];  
  16.         CV_DbgAssert(udata < (uchar*)ptr &&  
  17.                ((uchar*)ptr - udata) <= (ptrdiff_t)(sizeof(void*)+CV_MALLOC_ALIGN));   
  18.         free(udata);  
  19.     }  
  20. }  

其实内存多开了20字节的空间,其中4字节是用来存储这块空间的首地址的,用于释放空间时使用,还有16字节是用来调节地址,使地址达到16的倍数,CV_MALLOC_ALIGN在这里是16.

看一下alignPtr这个就是将地址向上调整至16的倍数,udata+1这里是指针加法,其实加的是sizeof(uchar**) 也就是4,这个4字节就是用来存首地址的,为什么要强转成uchar**,因为要访问这4个字节的内容,这个内容是个首地址,于是就是二级指针了。adata[-1]为什么这样?因为它先留出4字节之后在调整地址至16倍数,也就是实际存储数据的地址前还有至少4字节的空间,-1就是向前4字节,这个用来存首地址...

具体参考这篇博客http://blog.csdn.net/lming_08/article/details/26821963?utm_source=tuicool&utm_medium=referral

这个也值得学习

[cpp]  view plain  copy
  1. template<typename _Tp> inline void Ptr<_Tp>::addref()  
  2. if( refcount ) CV_XADD(refcount, 1); }  

CV_XADD实际上是一个宏,对应了无锁化编程,类似后置自增运算,返回原值之后再增加,不过这个无锁化可以用于多线程编程,用户自己无需再维护锁了。

具体参考这篇博客:http://blog.csdn.net/hzhsan/article/details/25124901

[cpp]  view plain  copy
  1. template<typename _Tp> inline void Ptr<_Tp>::release()  
  2. {  
  3.     if( refcount && CV_XADD(refcount, -1) == 1 )  
  4.     {  
  5.         delete_obj();  
  6.         fastFree(refcount);  
  7.     }  
  8.     refcount = 0;  
  9.     obj = 0;  
  10. }  
  11.   
  12. template<typename _Tp> inline void Ptr<_Tp>::delete_obj()  
  13. {  
  14.     if( obj ) delete obj;  
  15. }  
  16.   
  17. template<typename _Tp> inline Ptr<_Tp>::~Ptr() { release(); }  

注意这里的delete_obj是个泛化版本,对于无法delete的,需要实现一个特化版本。

其他构造函数

[cpp]  view plain  copy
  1. template<typename _Tp> inline Ptr<_Tp>::Ptr(const Ptr<_Tp>& ptr)  
  2. {  
  3.     obj = ptr.obj;  
  4.     refcount = ptr.refcount;  
  5.     addref();  
  6. }  
  7.   
  8. template<typename _Tp> inline Ptr<_Tp>& Ptr<_Tp>::operator = (const Ptr<_Tp>& ptr)  
  9. {  
  10.     int* _refcount = ptr.refcount;  
  11.     if( _refcount )  
  12.         CV_XADD(_refcount, 1);  
  13.     release();  
  14.     obj = ptr.obj;  
  15.     refcount = _refcount;  
  16.     return *this;  
  17. }  


注意拷贝构造函数,参数对应的对象无需释放,所以引用数加1,而赋值构造函数则需要先释放掉参数对应的对象,这是区别。

[cpp]  view plain  copy
  1. template<typename _Tp> inline _Tp* Ptr<_Tp>::operator -> () { return obj; }  
  2. template<typename _Tp> inline const _Tp* Ptr<_Tp>::operator -> () const { return obj; }  
  3.   
  4. template<typename _Tp> inline Ptr<_Tp>::operator _Tp* () { return obj; }  
  5. template<typename _Tp> inline Ptr<_Tp>::operator const _Tp*() const { return obj; }  
  6.   
  7. template<typename _Tp> inline bool Ptr<_Tp>::empty() const { return obj == 0; }  

关于->的重载非常奇怪,竟然无参数的,返回值必须是object*,但是->貌似又被object*共用去访问成员了...

具体参考这篇博客:http://blog.csdn.net/zhuxiufenghust/article/details/5708167


到此为止,我们大概知道如何自己实现一个智能指针类了...

  1.  generic_type ref-counting pointer class for C/C++ objects   
  2.   
  3. /*! 
  4.   Smart pointer to dynamically allocated objects. 
  5.  
  6.   This is template pointer-wrapping class that stores the associated reference counter along with the 
  7.   object pointer. The class is similar to std::smart_ptr<> from the recent addons to the C++ standard, 
  8.   but is shorter to write :) and self-contained (i.e. does add any dependency on the compiler or an external library). 
  9.  
  10.   Basically, you can use "Ptr<MyObjectType> ptr" (or faster "const Ptr<MyObjectType>& ptr" for read-only access) 
  11.   everywhere instead of "MyObjectType* ptr", where MyObjectType is some C structure or a C++ class. 
  12.   To make it all work, you need to specialize Ptr<>::delete_obj(), like: 
  13.  
  14.   \code 
  15.   template<> void Ptr<MyObjectType>::delete_obj() { call_destructor_func(obj); } 
  16.   \endcode 
  17.  
  18.   \note{if MyObjectType is a C++ class with a destructor, you do not need to specialize delete_obj(), 
  19.   since the default implementation calls "delete obj;"} 
  20.  
  21.   \note{Another good property of the class is that the operations on the reference counter are atomic, 
  22.   i.e. it is safe to use the class in multi-threaded applications} 
  23. */  
  24. template<typename _Tp> class CV_EXPORTS Ptr  
  25. {  
  26. public:  
  27.     //! empty constructor  
  28.     Ptr();  
  29.     //! take ownership of the pointer. The associated reference counter is allocated and set to 1  
  30.     Ptr(_Tp* _obj);  
  31.     //! calls release()  
  32.     ~Ptr();  
  33.     //! copy constructor. Copies the members and calls addref()  
  34.     Ptr(const Ptr& ptr);  
  35.     //! copy operator. Calls ptr.addref() and release() before copying the members  
  36.     Ptr& operator = (const Ptr& ptr);  
  37.     //! increments the reference counter  
  38.     void addref();  
  39.     //! decrements the reference counter. If it reaches 0, delete_obj() is called  
  40.     void release();  
  41.     //! deletes the object. Override if needed  
  42.     void delete_obj();  
  43.     //! returns true iff obj==NULL  
  44.     bool empty() const;  
  45.   
  46.   
  47.     //! helper operators making "Ptr<T> ptr" use very similar to "T* ptr".  
  48.     _Tp* operator -> ();  
  49.     const _Tp* operator -> () const;  
  50.   
  51.     operator _Tp* ();  
  52.     operator const _Tp*() const;  
  53.   
  54. protected:  
  55.     _Tp* obj; //< the object pointer.  
  56.     int* refcount; //< the associated reference counter  
  57. };  

所谓的智能指针,其实就是模板参数可以是任意的c++类,但考虑到对象在使用完毕的时候需要析构,因此要求特化delete_obj()函数。

接下来看源码

[cpp]  view plain  copy
  1. template<typename _Tp> inline Ptr<_Tp>::Ptr() : obj(0), refcount(0) {}  
  2. template<typename _Tp> inline Ptr<_Tp>::Ptr(_Tp* _obj) : obj(_obj)  
  3. {  
  4.     if(obj)  
  5.     {  
  6.         refcount = (int*)fastMalloc(sizeof(*refcount));  
  7.         *refcount = 1;  
  8.     }  
  9.     else  
  10.         refcount = 0;  
  11. }  
obj显然是指向对象的指针,refcount是引用数,默认构造函数就构造了一个空对象,带参数的构造函数则需要动态分配内存,当然如果参数传入NULL的话,就与默认构造函数没有区别了...注意这里使用了fastMalloc这个函数,使用了对齐指针的技术...
[cpp]  view plain  copy
  1. void* fastMalloc( size_t size )  
  2. {  
  3.     uchar* udata = (uchar*)malloc(size + sizeof(void*) + CV_MALLOC_ALIGN);  
  4.     if(!udata)  
  5.         return OutOfMemoryError(size);  
  6.     uchar** adata = alignPtr((uchar**)udata + 1, CV_MALLOC_ALIGN);  
  7.     adata[-1] = udata;  
  8.     return adata;  
  9. }  
  10.       
  11. void fastFree(void* ptr)  
  12. {  
  13.     if(ptr)  
  14.     {  
  15.         uchar* udata = ((uchar**)ptr)[-1];  
  16.         CV_DbgAssert(udata < (uchar*)ptr &&  
  17.                ((uchar*)ptr - udata) <= (ptrdiff_t)(sizeof(void*)+CV_MALLOC_ALIGN));   
  18.         free(udata);  
  19.     }  
  20. }  

其实内存多开了20字节的空间,其中4字节是用来存储这块空间的首地址的,用于释放空间时使用,还有16字节是用来调节地址,使地址达到16的倍数,CV_MALLOC_ALIGN在这里是16.

看一下alignPtr这个就是将地址向上调整至16的倍数,udata+1这里是指针加法,其实加的是sizeof(uchar**) 也就是4,这个4字节就是用来存首地址的,为什么要强转成uchar**,因为要访问这4个字节的内容,这个内容是个首地址,于是就是二级指针了。adata[-1]为什么这样?因为它先留出4字节之后在调整地址至16倍数,也就是实际存储数据的地址前还有至少4字节的空间,-1就是向前4字节,这个用来存首地址...

具体参考这篇博客http://blog.csdn.net/lming_08/article/details/26821963?utm_source=tuicool&utm_medium=referral

这个也值得学习

[cpp]  view plain  copy
  1. template<typename _Tp> inline void Ptr<_Tp>::addref()  
  2. if( refcount ) CV_XADD(refcount, 1); }  

CV_XADD实际上是一个宏,对应了无锁化编程,类似后置自增运算,返回原值之后再增加,不过这个无锁化可以用于多线程编程,用户自己无需再维护锁了。

具体参考这篇博客:http://blog.csdn.net/hzhsan/article/details/25124901

[cpp]  view plain  copy
  1. template<typename _Tp> inline void Ptr<_Tp>::release()  
  2. {  
  3.     if( refcount && CV_XADD(refcount, -1) == 1 )  
  4.     {  
  5.         delete_obj();  
  6.         fastFree(refcount);  
  7.     }  
  8.     refcount = 0;  
  9.     obj = 0;  
  10. }  
  11.   
  12. template<typename _Tp> inline void Ptr<_Tp>::delete_obj()  
  13. {  
  14.     if( obj ) delete obj;  
  15. }  
  16.   
  17. template<typename _Tp> inline Ptr<_Tp>::~Ptr() { release(); }  

注意这里的delete_obj是个泛化版本,对于无法delete的,需要实现一个特化版本。

其他构造函数

[cpp]  view plain  copy
  1. template<typename _Tp> inline Ptr<_Tp>::Ptr(const Ptr<_Tp>& ptr)  
  2. {  
  3.     obj = ptr.obj;  
  4.     refcount = ptr.refcount;  
  5.     addref();  
  6. }  
  7.   
  8. template<typename _Tp> inline Ptr<_Tp>& Ptr<_Tp>::operator = (const Ptr<_Tp>& ptr)  
  9. {  
  10.     int* _refcount = ptr.refcount;  
  11.     if( _refcount )  
  12.         CV_XADD(_refcount, 1);  
  13.     release();  
  14.     obj = ptr.obj;  
  15.     refcount = _refcount;  
  16.     return *this;  
  17. }  


注意拷贝构造函数,参数对应的对象无需释放,所以引用数加1,而赋值构造函数则需要先释放掉参数对应的对象,这是区别。

[cpp]  view plain  copy
  1. template<typename _Tp> inline _Tp* Ptr<_Tp>::operator -> () { return obj; }  
  2. template<typename _Tp> inline const _Tp* Ptr<_Tp>::operator -> () const { return obj; }  
  3.   
  4. template<typename _Tp> inline Ptr<_Tp>::operator _Tp* () { return obj; }  
  5. template<typename _Tp> inline Ptr<_Tp>::operator const _Tp*() const { return obj; }  
  6.   
  7. template<typename _Tp> inline bool Ptr<_Tp>::empty() const { return obj == 0; }  

关于 - >的重载非常奇怪,竟然无参数的,返回值必须是对象*,但是 - >貌似又被物体*共用去访问成员了......

具体参考这篇博客:http : //blog.csdn.net/zhuxiufenghust/article/details/5708167


到此为止,我们大概知道如何自己实现一个智能指针类了...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值