love in C++, live on MFC

to get ready...

C++博客 首页 新随笔 联系 聚合 管理
  47 Posts :: 0 Stories :: 97 Comments :: 0 Trackbacks
在《工作中发现的 》中,提到析构函数可以自己调用,并用一个例子编译、运行证明了。
现在有个问题,除了知道“析构函数可以自己调用”外,那么什么时候必须显式调用析构函数?

先看一段现实生活中的代码吧,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; }
但是,为什么不就直接调用构造函数呢?我也不知道。详见dhong下面的评论。(dhong纠正了我的一个错误)

不过,下面的代码
        CString aStr;
        CString
* pStr = &aStr ;
        pStr
->CString();

是编译不过的。

 

posted on 2006-03-04 00:35 flyingxu 阅读(11306) 评论(7)  编辑 收藏 引用 所属分类: C/C++

Feedback

# re: 什么时候必须显式调用析构函数? 2006-03-04 01:37 dhong
构造函数显式调用:
new (pStr) CString();

您需要直接学c++,而不是从mfc学c++  回复  更多评论
  

# 为什么不就直接调用构造函数呢? 2006-03-04 10:18 力为
placement new/delete:
EC++和MEC++有详细的解释。

--------------------------------------------
delete和free有什么区别?什么时候必须显式调用析构函数?
还得从对象的构造说起。对象的构造方式决定了它的析构方式。
C++提供了自定义new和delete的机制,程序员可以自己实现内存的分配释放策略。
具体还是看看EC++和MEC++

  回复  更多评论
  

# re: 什么时候必须显式调用析构函数? 2006-03-04 14:01 笑笑生
呵呵,挺好的,还是不要自己调用析构  回复  更多评论
  

# re: 什么时候必须显式调用析构函数? 2006-03-13 17:34 沐枫网志
楼主其实如果能够再加以说明,为什么需要调用析构函数,以及在什么情况下应该调用析构函数,这样就太好了。

而这篇随笔里头,只看到因调用析构函数而带来的快感--cool.  回复  更多评论
  

# re: 什么时候必须显式调用析构函数? 2006-03-16 17:12 stone
建议:万不得已时才使用“placement new”语法。只有当你真的在意对象在内存中的特定位置时才使用它。例如,你的硬件有一个内存映象的 I/O计时器设备,并且你想放置一个Clock对象在那个内存位置。

危险:你要独自承担这样的责任,传递给“placement new”操作符的指针所指向的内存区域必须足够大,并且可能需要为所创建的对象进行边界调整。编译器和运行时系统都不会进行任何的尝试来检查你做的是否正确。
  回复  更多评论
  

# re: 什么时候必须显式调用析构函数? 2006-03-16 17:14 flyingxu
@沐枫网志
简单的说吧:

为什么需要调用析构函数?
当然是为了让该对象做释放资源的善后工作

以及在什么情况下应该调用析构函数?
想让对象释放它运行中分配的内存,但是对象本身的内存不释放(比如对象中还还有指向另一块内存的指针时的情况),或者不能用delete释放,比如例子中时用calloc分配的内存是不能用delete释放的  回复  更多评论
  

# re: 什么时候必须显式调用析构函数?[未登录] 2015-04-07 20:31 111
@dhong
可以调用pStr->CString::CString();  回复  更多评论
  


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理