1. 安全指针
从opencv2.0开始,很多C数据结构变成了C++的类,考虑到兼容性,保留旧的API。在内存管理方面,提供安全指针类Ptr,让在此以前旧的需要手动管理内存的数据结构(IplImage, CvMat等)无需手动Release,用法为:
Ptr<IplImage> img = cvReadImage("Lena.jpg");
Ptr是一个模板类,在opencv中定义如下:
template<typename _Tp> class Ptr
{
public:
Ptr();
Ptr(_Tp* _obj);
~Ptr();
Ptr(const Ptr& ptr);
Ptr& operator = (const Ptr& ptr);
void addref();
void release();
void delete_obj();
bool empty() const;
_Tp* operator -> ();
const _Tp* operator -> () const;
operator _Tp* ();
operator const _Tp*() const;
protected:
_Tp* obj;
int* refcount;
};
上述源码定义在原有的指针类加了个指针引用数(refcount),对一些操作符进行了重载(operator ->;())。值得注意的是,Ptr template 对指针指向的对象有一个要求,就是可以用 delete 操作土符来释放内存。你可能就想到 IplImage 就不满足这个要求了,这怎么办?可以使用模板特化(template specialization)重载 Ptr<Iplimage>::delete_obj() 函数:
template<> inline void Ptr<IplImage>::delete_obj()
{ cvReleaseImage(&obj); }
2. 指针对齐(http://bytes.com/topic/c/answers/213142-what-pointer-alignment)
为什么要指针对齐? 这是因为在某些架构上,只有能被指定数(如4,16)整除的内存地址才能够被访问,否则程序会crash,或者出现错误的结果,或者数据的访问变慢。举个例子来说,很多系统都要求interger的地址从偶数开始。opencv2.0以上版本很多指针都是被对齐过的,使指针地址能够被16整除。opencv中的内存一般是通过malloc分配,不能保证都是都能被16整除,此时需要截断,但是剩下的内存要如何维护? CV2.0的这样维护的:在 malloc 是多申请一个指针的空间,这个指针指向 malloc 得到的真实内存地址,只在 free 时使用它。相关函数:
typedef unsigned char uchar;
#define CV_MALLOC_ALIGN 16
template<typename _Tp> static inline _Tp* alignPtr(_Tp* ptr, int n=(int)sizeof(_Tp))
{
return (_Tp*)(((size_t)ptr + n-1) & -n);
}
__declspec(dllexport) void* fastMalloc( size_t size )
{
uchar* udata = (uchar*)malloc(size + sizeof(void*) + CV_MALLOC_ALIGN); //HERE 多申请一个 void* 的空间用于存储 udata
uchar** adata = alignPtr((uchar**)udata + 1, CV_MALLOC_ALIGN);
adata[-1] = udata; //<- 存储 udata
return adata;
}
__declspec(dllexport) void fastFree(void* ptr)
{
if(ptr)
{
uchar* udata = ((uchar**)ptr)[-1];
assert(udata < (uchar*)ptr && ((uchar*)ptr - udata) <= (ptrdiff_t)(sizeof(void*)+CV_MALLOC_ALIGN));
free(udata);
}
}