事情的经过是这样的,我在实现一个基于OpenCv的CImage类。我需要实现它的拷贝构造函数,因为我要把它push_back到vector里面去。我过去的一直做法是在赋值操作符中实现真正的操作,在拷贝构造函数中调用。但是在这里却出现了内存错误。
好歹我还写过几年程序,那我就开始了艰辛的调试。经过调试我发现,我的程序一直只进入拷贝构造函数,然后进去赋值操作符,在赋值操作符中我释放了对象原有的内存。错误就出现在了这里。按照我这种写法的理解,push_back是先用默认构造函数构造对象加入vector,然后再用原有拷贝构造函数初始化内容,或者说用赋值操作符初始化内容。
事实上,完全不是这样的。push_back直接添加新的内存,然后对这块新的内存用拷贝构造函数初始化而已。既然这样的话,拷贝构造函数是不能够直接调用赋值操作符的。应该再重新写一个真正的赋值子函数,拷贝构造函数和赋值操作符都调用这个子函数。赋值操作符中多了一个先检查是否同一个对象,如果不是同一个则释放原有内存的过程而已。
具体的可以看,CImage的部分代码。
class CImage { public: CImage(); ~CImage(); CImage(const CImage yxImage); CImage operator =(const CImage yxImage);//深度拷贝 private: void CopyData(const CImage yxImage); };
CImage::CImage(void) { m_pImg = NULL; m_ppfData = NULL; m_pfData = NULL; } CImage::CImage(const char* pcszName) { m_pImg = NULL; m_ppfData = NULL; m_pfData = NULL; Load(pcszName); } CImage::~CImage(void) { UnInit(); } void CImage::CopyData(const CImage yxImage) { m_pImg = cvCloneImage(yxImage.m_pImg); m_nRows = m_pImg->height; m_nCols = m_pImg->width * m_pImg->nChannels; int nLineSize = m_nCols * sizeof(double); m_ppfData = new double*[m_nRows]; m_pfData = new double[m_nRows * m_nCols]; for (int i = 0; i < m_pImg->height; ++i) { m_ppfData[i] = m_pfData[i * m_nCols]; memcpy(m_ppfData[i], yxImage[i], nLineSize); } } CImage::CImage(const CImage yxImage)//复制构造函数 { //*this = yxImage;//不能用=来实现,否则在push_back时候会出现内存错误,因为vector不调用默认构造函数 //而是先添加对象的内存,再用复制构造函数初始化数据 CopyData(yxImage); } CImage CImage::operator=(const CImage yxImage) { if (this == yxImage) { return *this; } UnInit(); CopyData(yxImage); return *this; }