- 垫M(200,200,CV_64F);
- for (int i = 0; i <M.rows; i ++)
- {
- for (int j = 0; j <M.cols; j ++)
- M.at < double >(i,j)= CV_PI;
- }
- /笔记
- 请注意at <>方法效率不高,因为它必须精确计算
- 内存位置从像素行和列。这可能非常耗时
- 当我们逐像素地处理整个图像时。第二种方法使用ptr
- 函数,它返回指向特定图像行的指针。以下片段
- 获取彩色图像中每个像素的像素值:
- /节省处理时间的方式,用PTR函数,返回一个指向图像行的指针。
- uchar R,G,B;
- for (int i = 0; i <src2.rows; i ++)
- {
- Vec3b * pixrow = src2.ptr <Vec3b>(i);
- for (int j = 0; j <src2.cols; j ++)
- {
- B = pixrow [j] [0];
- G = pixrow [j] [1];
- R = pixrow [j] [2];
- }
- }
- 笔记
- 在上面的示例中,ptr用于获取指向每行中第一个像素的指针。
- 使用 这个 指针,我们现在可以访问最内层循环中的每一列。
- C / C ++对象的generic_type ref-counting指针类/// /
- / *!
- 智能指针指向动态分配的对象。
- 这是模板指针环绕类,用于存储关联的引用计数器
- 对象指针。该类与最近的C ++标准插件中的std :: smart_ptr <>类似,
- 但编写时间更短)和自包含的(即在编译器或外部库中添加了任何依赖关系)。
- 基本上,您可以使用“Ptr <MyObjectType> ptr”(或更快的“const Ptr <MyObjectType>&ptr”进行只读访问)
- 处处代替“MyObjectType * ptr”,其中MyObjectType是一些C结构或C ++类。
- 为了使这一切工作,你需要专门Ptr <> :: delete_obj(),如:
- \码
- template <> void Ptr <MyObjectType> :: delete_obj(){call_destructor_func(obj); }
- \ endcode
- \注意{如果MyObjectType是一个具有析构函数的C ++类,则不需要专门化delete_obj(),
- 因为默认实现调用“delete obj;”}
- \注意{这个类的另一个好的属性是参考计数器上的操作是原子的,
- 即在多线程应用程序中使用该类是安全的}
- * /
- 模板< typename _Tp> class CV_EXPORTS Ptr
- {
- 公众:
- //!空的构造函数
- PTR();
- //!掌握指针的所有权。关联的引用计数器被分配并设置为1
- Ptr(_Tp * _obj);
- //!调用release()
- 〜PTR();
- //!复制构造函数。复制成员并调用addref()
- Ptr(const Ptr&ptr);
- //!复制操作员。在复制成员之前调用ptr.addref()和release()
- Ptr&operator =(const Ptr&ptr);
- //!增加参考计数器
- void addref();
- //!递减参考计数器。如果它达到0,则调用delete_obj()
- void release();
- //!删除对象。如果需要覆盖
- void delete_obj();
- //!返回true iff obj == NULL
- bool empty() const ;
- //!使“Ptr <T> ptr”的辅助操作符与“T * ptr”非常相似。
- _Tp *运算符 - >();
- const _Tp * operator - >() const ;
- operator _Tp* ();
- operator const _Tp*() const;
- protected:
- _Tp* obj; //< the object pointer.
- int* refcount; //< the associated reference counter
- };
所谓的智能指针,其实就是模板参数可以是任意的c++类,但考虑到对象在使用完毕的时候需要析构,因此要求特化delete_obj()函数。
接下来看源码
- template<typename _Tp> inline Ptr<_Tp>::Ptr() : obj(0), refcount(0) {}
- template<typename _Tp> inline Ptr<_Tp>::Ptr(_Tp* _obj) : obj(_obj)
- {
- if(obj)
- {
- refcount = (int*)fastMalloc(sizeof(*refcount));
- *refcount = 1;
- }
- else
- refcount = 0;
- }
- void* fastMalloc( size_t size )
- {
- uchar* udata = (uchar*)malloc(size + sizeof(void*) + CV_MALLOC_ALIGN);
- if(!udata)
- return OutOfMemoryError(size);
- uchar** adata = alignPtr((uchar**)udata + 1, CV_MALLOC_ALIGN);
- adata[-1] = udata;
- return adata;
- }
- void fastFree(void* ptr)
- {
- if(ptr)
- {
- uchar* udata = ((uchar**)ptr)[-1];
- CV_DbgAssert(udata < (uchar*)ptr &&
- ((uchar*)ptr - udata) <= (ptrdiff_t)(sizeof(void*)+CV_MALLOC_ALIGN));
- free(udata);
- }
- }
其实内存多开了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
这个也值得学习
- template<typename _Tp> inline void Ptr<_Tp>::addref()
- { if( refcount ) CV_XADD(refcount, 1); }
CV_XADD实际上是一个宏,对应了无锁化编程,类似后置自增运算,返回原值之后再增加,不过这个无锁化可以用于多线程编程,用户自己无需再维护锁了。
具体参考这篇博客:http://blog.csdn.net/hzhsan/article/details/25124901
- template<typename _Tp> inline void Ptr<_Tp>::release()
- {
- if( refcount && CV_XADD(refcount, -1) == 1 )
- {
- delete_obj();
- fastFree(refcount);
- }
- refcount = 0;
- obj = 0;
- }
- template<typename _Tp> inline void Ptr<_Tp>::delete_obj()
- {
- if( obj ) delete obj;
- }
- template<typename _Tp> inline Ptr<_Tp>::~Ptr() { release(); }
注意这里的delete_obj是个泛化版本,对于无法delete的,需要实现一个特化版本。
其他构造函数
- template<typename _Tp> inline Ptr<_Tp>::Ptr(const Ptr<_Tp>& ptr)
- {
- obj = ptr.obj;
- refcount = ptr.refcount;
- addref();
- }
- template<typename _Tp> inline Ptr<_Tp>& Ptr<_Tp>::operator = (const Ptr<_Tp>& ptr)
- {
- int* _refcount = ptr.refcount;
- if( _refcount )
- CV_XADD(_refcount, 1);
- release();
- obj = ptr.obj;
- refcount = _refcount;
- return *this;
- }
注意拷贝构造函数,参数对应的对象无需释放,所以引用数加1,而赋值构造函数则需要先释放掉参数对应的对象,这是区别。
- template<typename _Tp> inline _Tp* Ptr<_Tp>::operator -> () { return obj; }
- template<typename _Tp> inline const _Tp* Ptr<_Tp>::operator -> () const { return obj; }
- template<typename _Tp> inline Ptr<_Tp>::operator _Tp* () { return obj; }
- template<typename _Tp> inline Ptr<_Tp>::operator const _Tp*() const { return obj; }
- template<typename _Tp> inline bool Ptr<_Tp>::empty() const { return obj == 0; }
关于->的重载非常奇怪,竟然无参数的,返回值必须是object*,但是->貌似又被object*共用去访问成员了...
具体参考这篇博客:http://blog.csdn.net/zhuxiufenghust/article/details/5708167
到此为止,我们大概知道如何自己实现一个智能指针类了...
- generic_type ref-counting pointer class for C/C++ objects
- /*!
- Smart pointer to dynamically allocated objects.
- This is template pointer-wrapping class that stores the associated reference counter along with the
- object pointer. The class is similar to std::smart_ptr<> from the recent addons to the C++ standard,
- but is shorter to write :) and self-contained (i.e. does add any dependency on the compiler or an external library).
- Basically, you can use "Ptr<MyObjectType> ptr" (or faster "const Ptr<MyObjectType>& ptr" for read-only access)
- everywhere instead of "MyObjectType* ptr", where MyObjectType is some C structure or a C++ class.
- To make it all work, you need to specialize Ptr<>::delete_obj(), like:
- \code
- template<> void Ptr<MyObjectType>::delete_obj() { call_destructor_func(obj); }
- \endcode
- \note{if MyObjectType is a C++ class with a destructor, you do not need to specialize delete_obj(),
- since the default implementation calls "delete obj;"}
- \note{Another good property of the class is that the operations on the reference counter are atomic,
- i.e. it is safe to use the class in multi-threaded applications}
- */
- template<typename _Tp> 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 members and calls addref()
- 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() is called
- void release();
- //! deletes the object. Override if needed
- void delete_obj();
- //! returns true iff obj==NULL
- bool empty() const;
- //! helper operators making "Ptr<T> ptr" use very similar to "T* ptr".
- _Tp* operator -> ();
- const _Tp* operator -> () const;
- operator _Tp* ();
- operator const _Tp*() const;
- protected:
- _Tp* obj; //< the object pointer.
- int* refcount; //< the associated reference counter
- };
所谓的智能指针,其实就是模板参数可以是任意的c++类,但考虑到对象在使用完毕的时候需要析构,因此要求特化delete_obj()函数。
接下来看源码
- template<typename _Tp> inline Ptr<_Tp>::Ptr() : obj(0), refcount(0) {}
- template<typename _Tp> inline Ptr<_Tp>::Ptr(_Tp* _obj) : obj(_obj)
- {
- if(obj)
- {
- refcount = (int*)fastMalloc(sizeof(*refcount));
- *refcount = 1;
- }
- else
- refcount = 0;
- }
- void* fastMalloc( size_t size )
- {
- uchar* udata = (uchar*)malloc(size + sizeof(void*) + CV_MALLOC_ALIGN);
- if(!udata)
- return OutOfMemoryError(size);
- uchar** adata = alignPtr((uchar**)udata + 1, CV_MALLOC_ALIGN);
- adata[-1] = udata;
- return adata;
- }
- void fastFree(void* ptr)
- {
- if(ptr)
- {
- uchar* udata = ((uchar**)ptr)[-1];
- CV_DbgAssert(udata < (uchar*)ptr &&
- ((uchar*)ptr - udata) <= (ptrdiff_t)(sizeof(void*)+CV_MALLOC_ALIGN));
- free(udata);
- }
- }
其实内存多开了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
这个也值得学习
- template<typename _Tp> inline void Ptr<_Tp>::addref()
- { if( refcount ) CV_XADD(refcount, 1); }
CV_XADD实际上是一个宏,对应了无锁化编程,类似后置自增运算,返回原值之后再增加,不过这个无锁化可以用于多线程编程,用户自己无需再维护锁了。
具体参考这篇博客:http://blog.csdn.net/hzhsan/article/details/25124901
- template<typename _Tp> inline void Ptr<_Tp>::release()
- {
- if( refcount && CV_XADD(refcount, -1) == 1 )
- {
- delete_obj();
- fastFree(refcount);
- }
- refcount = 0;
- obj = 0;
- }
- template<typename _Tp> inline void Ptr<_Tp>::delete_obj()
- {
- if( obj ) delete obj;
- }
- template<typename _Tp> inline Ptr<_Tp>::~Ptr() { release(); }
注意这里的delete_obj是个泛化版本,对于无法delete的,需要实现一个特化版本。
其他构造函数
- template<typename _Tp> inline Ptr<_Tp>::Ptr(const Ptr<_Tp>& ptr)
- {
- obj = ptr.obj;
- refcount = ptr.refcount;
- addref();
- }
- template<typename _Tp> inline Ptr<_Tp>& Ptr<_Tp>::operator = (const Ptr<_Tp>& ptr)
- {
- int* _refcount = ptr.refcount;
- if( _refcount )
- CV_XADD(_refcount, 1);
- release();
- obj = ptr.obj;
- refcount = _refcount;
- return *this;
- }
注意拷贝构造函数,参数对应的对象无需释放,所以引用数加1,而赋值构造函数则需要先释放掉参数对应的对象,这是区别。
- template<typename _Tp> inline _Tp* Ptr<_Tp>::operator -> () { return obj; }
- template<typename _Tp> inline const _Tp* Ptr<_Tp>::operator -> () const { return obj; }
- template<typename _Tp> inline Ptr<_Tp>::operator _Tp* () { return obj; }
- template<typename _Tp> inline Ptr<_Tp>::operator const _Tp*() const { return obj; }
- template<typename _Tp> inline bool Ptr<_Tp>::empty() const { return obj == 0; }
关于 - >的重载非常奇怪,竟然无参数的,返回值必须是对象*,但是 - >貌似又被物体*共用去访问成员了......
具体参考这篇博客:http : //blog.csdn.net/zhuxiufenghust/article/details/5708167
到此为止,我们大概知道如何自己实现一个智能指针类了...