两个让人头痛的问题~~~高手进
1.析构函数内释放指针的时候,指针会被重复释放的问题
根据原来的程序构造了一个简单的类再现问题:
class A
{
public:
A()
{
a=10;
Create();
}
~A()
{
if (p!=NULL) //F9加breakpoint的位置
{
delete [] p;
p=NULL;
}
}
int *Create()
{
p=new int[100];
return p; }
A operator -(A a)
{
A m_R(10);
return m_R; //F9加BreakPoint
}
private:
int a;
int *p;
};
调用这个类的
void CTestDlg::OnOk(){
A a,b,c;
c=a-b; /*****************************/
}
单步运行程序会发现重载操作符函数中两个类a和m_R的指针都被正确释放,假设这两个类中p的地址为addr1,addr2,但在OnOk函数结束释放b类的时候又一个地址为addr1的p指针被释放,但这时虽然p不为NULL,但是运行到析构函数中的delete [] p;语句的时候编译器就会抛出一个保护性的ASSERT,我只是简单的重构了这个函数,释放内存从析构函数中拿出来,大家都是怎么解决这个问题的呢?
第二个问题:
在构造函数中调用了一个成员函数,该成员函数调用了一个纯虚函数,派生类实现了这个纯虚函数,并重载了一个操作符,当用派生类实例化一个对象以后,不调用重载的操作符函数什么问题没有,一旦调用该函数并在该函数中利用拷贝构造函数创建一个对象,则编译器马上抛出“R6025:pure virtual function call”的异常,找不到在没有实现纯虚函数前就调用的位置,集思广益一下,看看还有什么原因造成这个问题的。。。
[解决办法]
关于第一个问题,原因是你将a-b赋给了C,而你没有定义=运算符,所以调用默认的=运算符,直接拷贝了指针而不是指针指向的内容,也就是说C里的指针和你的operator -里面的临时变量m_R指向同一内容;而m_R被释放后指针指向的内存也被释放,再析构C的时候当然要出问题了
要记住的是如果类里有指针的话一般要定义copy构造函数,=操作符以及析构函数,而你只定义了析构函数.
[解决办法]
第一个问题,是一个典型的动态内存分配的问题,如blackmurder(blackmurder)说的,你进行的是浅拷贝(只进行指针的复制),同时,在A operator -(A a)函数中,不实用引用,这样,在进行对象施放是,将同一块内存施放了两次,所以会出错。
这里,可以通过两个方向进行修改:
1,最好是重写copy constructor。对对象维护的指针重新内存分配。避免以后不小心的错误。
2, 将A operator -(A a)函数中的返回类型和型参都改为引用,避免临时对象的产生。(这里的返回类型和型参都回造成临时对象的生成)。
目前就发现了这两点。还请高手指教。
[解决办法]
第二个问题,构造函数的功能之一,是对虚表进行填充(MS的解决方案),而父类的构造函数永远比子类的早,所以,在子类中重写的虚函数,这时是没有填充到虚表中的,所以,在父类的构造函数中调用虚函数,永远只可能调用到该类的实现或该类以上的实现(该类没有重写)。
愚见!