什么时候必须显式调用析构函数
析构函数可以自己调用
msdn says:
Calling a destructor explicitly is seldom necessary. However, it can be useful to perform cleanup of objects placed at absolute addresses. These objects are commonly allocated using a user-defined new operator that takes a placement argument. The delete operator cannot deallocate this memory because it is not allocated from the free store . A call to the destructor, however, can perform appropriate cleanup. To explicitly call the destructor for an object, s, of class String, use one of the following statements:
s.String::~String(); // Nonvirtual call ps->String::~String(); // Nonvirtual call s.~String(); // Virtual call ps->~String(); // Virtual call
现在有个问题,除了知道 “析构函数可以自己调用” 外, 那么什么时候必须显式调用析构函数?
先看一段现实生活中的代码吧, mfc 源码:
BOOL CStatusBar::AllocElements(int nElements, int cbElement)
{
int i;
// destruct old elements
AFX_STATUSPANE* pSBP = _GetPanePtr(0);
for (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++)
{
#pragma push_macro("new")
#undef new
new( &pSBP->strText ) CString; // 注意看这里
#pragma pop_macro("new")
++pSBP;
}
return TRUE;
}
在上面的代码中,就有显式调用 CString 的析构函数的代码。cool。
因为还调用了CControlBar::AllocElements(),上面的代码不是很明显,我把CControlBar::AllocElements简化一下后:
BOOL CControlBar::AllocElements(int nElements, int cbElement)
{
ASSERT_VALID(this);
ENSURE_ARG(nElements >= 0 && cbElement >= 0);
ENSURE(m_pData != NULL || m_nCount == 0);
// allocate new data if necessary
void* pData = NULL;
if (nElements > 0)
{
ENSURE_ARG(cbElement > 0);
if ((pData = calloc(nElements, cbElement)) == NULL) // 注意这里 : calloc
return FALSE;
}
free(m_pData); // free old data // 注意这里 : free
// set new data and elements
m_pData = pData;
m_nCount = nElements;
return TRUE;
}
这个时候,如果注意到我特别注释的 free 函数调用,可能已经意识到了为什么要显式调用析构函数了。
如果还没有,那么可以问自己一个面试常规问题:delete和free有什么区别?答:delete会使析构函数被调用。
或者反过来说,free 没有调用析构函数,那么怎么办?所以你必须自己显式调用析构函数。
上面的这个例子可以这样抽象下,现在需要 free 掉一块内存,而那块内存中,还有一个类,类里面还有指针,(这里是CString)需要在析构函数中释放内存。因为用的是free,所以那个类的析构函数不会自动被调用,这个时候,就必须显式调用那个类的析构函数。
另外继续问个面试问题,new和calloc的区别?哈,构造的函数的调用啊
所以,上面的代码用的calloc,就必须显式调用构造函数啊,在哪里呢?就是
new( &pSBP->strText ) CString; // 注意看这里
不过,下面的代码
CString aStr; CString* pStr = &aStr ; pStr->CString();
是编译不过的。
建议:万不得已时才使用 “placement new” 语法。只有当你真的在意对象在内存中的特定位置时才使用它。例如,你的硬件有一个内存映象的 I/O计时器设备,并且你想放置一个Clock对象在那个内存位置。
危险:你要独自承担这样的责任,传递给“placement new”操作符的指针所指向的内存区域必须足够大,并且可能需要为所创建的对象进行边界调整。编译器和运行时系统都不会进行任何的尝试来检查你做的是否正确。
简单的说吧:
为什么需要调用析构函数? 当然是为了让该对象做释放资源的善后工作, 以及在什么情况下应该调用析构函数?
想让对象释放它运行中分配的内存,但是对象本身的内存不释放(比如对象中还还有指向另一块内存的指针时的情况),或者不能用 delete 释放, 比如例子中时用 calloc 分配的内存是不能用 delete 释放的.

近期评论