当先锋百科网

首页 1 2 3 4 5 6 7

[转] 一个帖子,很能说明这个问题

问题: 
以下这段代码执行后会不会有问题? 
基类: 
class CBase  

public: 
    virtual void VirtualFun1(CString strFun1) = 0; 
}; 

子类: 
class CDerived : public CBase  

public: 
    CDerived(); 
    virtual ~CDerived();    
    virtual void VirtualFun1(CString strFun1); 
private: 
    CString m_strFun1; 
}; 
CDerived::CDerived() 


CDerived::~CDerived() 


void CDerived::VirtualFun1(CString strFun1) 

    m_strFun1 = strFun1; 


客户代码: 
    CBase *pBase = new CDerived(); 
    pBase->VirtualFun1("test"); 
    delete pBase; 

答案/分析: 
会! 
只要一运行,就会发生内存泄漏(我的测试平台:VC6); 
调试器输出信息: 
Dumping objects -> 
strcore.cpp(118) : {76} normal block at 0x003A36E8, 16 bytes long. 
Data: <            tsr > 01 00 00 00 03 00 00 00 03 00 00 00 74 73 72 00 
Object dump complete. 
注: 
01 00 00 00 03 00 00 00 03 00 00 00 74 73 72 00 
这部分数据可能是调试器的内存保护数据,未验证 
问题表面是在于m_strFun1,问题的实质其实是CBase 没有提供虚拟析构函数,只要为CBase 加入一个虚拟析构函数即解决了上面的问题; 
原因就在于当delete pBase的时候,只是调用了CBase的析构函数(非虚拟,编译器背地里完成,对于纯虚拟类还没有验证过),从而导致未调用CDerived的析构函数,进而造成m_strFun1没有被释放内存。 
事后,查了一下资料,其实在《Effective C++》中的条款14中对此进行了详细的解释,有兴趣的可以去参考一下。 
如果单单分析这段代码,其实还是好解决的,如果把这段代码放到一个大程序中,出现类似的内存泄漏时,可能就很难追查了,所以还是要打好基础,写好每一行代码。 

总结: 
1. C++基本功不扎实,对析构函数了解不够,对编译器的内部行为不够了解; 
2. 忽视了代码的变化,特别是向导生成的代码,一般通过向导会自动建立一个虚拟析构函数; 
3. 发现问题的关键比解决问题更难;由于这个内存泄漏是发生在一个比较大的程序中,并且还涉及到其它dll,花了很长时间对它进行定位,确定发生泄漏的代码行; 
4. 调试是对基本知识的综合考验,最能反映一个人的技术深度,深入剥析后就能加深技术细节的理解和记忆;