在《
工作中发现的 》中,提到析构函数可以自己调用,并用一个例子编译、运行证明了。
现在有个问题,除了知道“析构函数
可以自己调用”外,那么什么时候
必须显式调用析构函数?
先看一段现实生活中的代码吧,mfc源码中:
BOOL CStatusBar::AllocElements(int nElements, int cbElement)
{
// destruct old elements
AFX_STATUSPANE* pSBP = _GetPanePtr(0);
for (int i = 0; i < m_nCount; i++)
{
pSBP->strText.~CString(); //注意看这里
++pSBP;
}
// allocate new elements
if (!CControlBar::AllocElements(nElements, cbElement))
return FALSE;
// construct new elements
pSBP = _GetPanePtr(0);
for (i = 0; i < m_nCount; i++)
{
memcpy(&pSBP->strText, &afxEmptyString, sizeof(CString));
++pSBP;
}
return TRUE;
}
在上面的代码中,就有显式调用CString的析构函数的代码。cool。
因为还调用了
CControlBar::AllocElements(),上面的代码不是很明显,我把CControlBar::AllocElements简化一下后:
BOOL CStatusBar::AllocElements(int nElements, int cbElement)
{
// destruct old elements
AFX_STATUSPANE* pSBP = _GetPanePtr(0);
for (int i = 0; i < m_nCount; i++)
{
pSBP->strText.~CString(); //注意看这里
++pSBP;
}
// allocate new elements
//if (!CControlBar::AllocElements(nElements, cbElement))
// return FALSE;
//简化后的代码,实际运行肯定有问题,但是关键东西出来了
free(pSBP);//注意这里调用的是free
pSBP = calloc(nElements, cbElement);
// construct new elements
pSBP = _GetPanePtr(0); //根据mfc的代码,可以理解这里的pSBP和前面的pSBP还是同一个地址
for (i = 0; i < m_nCount; i++)
{
memcpy(&pSBP->strText, &afxEmptyString, sizeof(CString));
++pSBP;
}
return TRUE;
}
这个时候,如果注意到我特别注释的free函数调用,可能已经意识到了为什么要显式调用析构函数了。
如果还没有,那么可以问自己一个面试常规问题:delete和free有什么区别?答:delete会使析构函数被调用。
或者反过来说,
free没有调用析构函数,那么怎么办?所以你必须自己显示调用析构函数。
上面的这个例子可以这样抽象下,现在需要free掉一块内存,而那块内存中,还有一个类,类里面还有指针,(这里是CString)需要在析构函数中释放内存。因为用的是free,所以那个类的析构函数不会自动被调用,这个时候,就
必须显式调用那个类的析构函数。
这个是不是很偏的问题呢?遇到了就看看,没有遇到过,也不会影响日常工作,哈。
另外继续问个面试问题,new和calloc的区别?哈,构造的函数的调用啊
所以,上面的代码用的calloc,就必须显示调用构造函数啊,在哪里呢?就是
memcpy(&pSBP->strText, &afxEmptyString, sizeof(CString));
和CString的构造函数比较下:
_AFX_INLINE CString::CString()
{ m_pchData = afxEmptyString.m_pchData; }
但是,为什么不就直接调用构造函数呢?我也不知道。详见下面的评论。(纠正了我的一个错误)
不过,下面的代码
CString aStr;
CString* pStr = &aStr ;
pStr->CString();
是编译不过的。