别调试,道出这小段代码的运行结果
别调试,说出这小段代码的运行结果
------解决方案--------------------
额,没看到那个没有virtual,那我来解释一下吧,由于父类中没有利用virtual来修饰析构,所以子类中的析构在调用时,仍然是调用父类中的析构,又由于,是派生关系,我在2L已经说明,与构造顺序相反,那么调用了2次父类析构,这样容易导致释放两次父类中内存空间,会崩掉!
------解决方案--------------------
应该是会调用基类的析构函数,但好像这是未定义行为,所以可能会崩掉。。
------解决方案--------------------
一般会崩掉吧,
在调用析构函数之后(因为基类是非虚拟析构函数,所以只调用到基类的析构函数),
在释放空间时可能会出错,因为一般动态申请内存时所返回的指针指向的内存之前的空间会保存这段内存的info(大小等信息),而这里的内存空间却是这样的:
info
vptr
base
所以当释放的时候会错误的把vptr当做info去处理去获得这段内存的信息,肯定会出错。
------解决方案--------------------
什么情况?调试下?
------解决方案--------------------
跟编译器有关? operator delete的地址必须是operator new返回的,否则行为未定义。
------解决方案--------------------
虽然子类的析构函数不会被调用,但应该不是主要问题。
------解决方案--------------------
看看effective c++条款14
------解决方案--------------------
c++语言标准关于这个问题的阐述非常清楚:当通过基类的指针去删除派生类的对象,而基类又没有虚析构函数时,结果将是不可确定的。这意味着编译器生成的代码将会做任何它喜欢的事:重新格式化你的硬盘,给你的老板发电子邮件,把你的程序源代码传真给你的对手,无论什么事都可能发生。
看看effective c++条款14
------解决方案--------------------
恩,能详细解释下不?
能说下析构函数是怎么确定Operator Delete()的地址的不?
------解决方案--------------------
基类析构函数没有说明为虚函数,而p是基类指针,所以只执行基类析构函数,输出:Base::destructor.
子类将不会被正确析构掉,造成内存泄露。
------解决方案--------------------
简单点说,出错原因和下面的出错类似:
int *p = new int[10];
delete[](p + 1);
因为基类没有虚拟函数而派生类有虚拟函数的时候,此时基类指针指向派生类对象的时候,会发生this指针偏移,如楼主所举的例子中:
Derived *pd = new Derived;
Base *pb = pd;
可以打印两者的值来看下,应该是不相等的;
在
delete pb;
时,由于基类析构函数不是虚拟函数,所以会首先执行基类的析构函数,然后执行operator delete pb;
这里就会出问题,因为申请的时候返回的值时pd,而pd != pb;
------解决方案--------------------
#include <stdio.h>
class Base
{
public:
~Base() {printf("\nBase::destructor.");}
};
class Derived: public Base
{
public:
virtual ~Derived(){printf("\nDerived::destructor.");}
};
void fun()
{
Base* p = new Derived;
delete p;
}
int main()
{
fun();
getchar();
}
------解决方案--------------------
额,没看到那个没有virtual,那我来解释一下吧,由于父类中没有利用virtual来修饰析构,所以子类中的析构在调用时,仍然是调用父类中的析构,又由于,是派生关系,我在2L已经说明,与构造顺序相反,那么调用了2次父类析构,这样容易导致释放两次父类中内存空间,会崩掉!
------解决方案--------------------
应该是会调用基类的析构函数,但好像这是未定义行为,所以可能会崩掉。。
------解决方案--------------------
一般会崩掉吧,
在调用析构函数之后(因为基类是非虚拟析构函数,所以只调用到基类的析构函数),
在释放空间时可能会出错,因为一般动态申请内存时所返回的指针指向的内存之前的空间会保存这段内存的info(大小等信息),而这里的内存空间却是这样的:
info
vptr
base
所以当释放的时候会错误的把vptr当做info去处理去获得这段内存的信息,肯定会出错。
------解决方案--------------------
什么情况?调试下?
------解决方案--------------------
跟编译器有关? operator delete的地址必须是operator new返回的,否则行为未定义。
Derived* pd = new Derived();
Base* p = pd;
delete p;//如果p == pd,可以正确的释放内存, 否则行为未定义
------解决方案--------------------
虽然子类的析构函数不会被调用,但应该不是主要问题。
------解决方案--------------------
c++语言标准关于这个问题的阐述非常清楚:当通过基类的指针去删除派生类的对象,而基类又没有虚析构函数时,结果将是不可确定的。这意味着编译器生成的代码将会做任何它喜欢的事:重新格式化你的硬盘,给你的老板发电子邮件,把你的程序源代码传真给你的对手,无论什么事都可能发生。
看看effective c++条款14
------解决方案--------------------
c++语言标准关于这个问题的阐述非常清楚:当通过基类的指针去删除派生类的对象,而基类又没有虚析构函数时,结果将是不可确定的。这意味着编译器生成的代码将会做任何它喜欢的事:重新格式化你的硬盘,给你的老板发电子邮件,把你的程序源代码传真给你的对手,无论什么事都可能发生。
看看effective c++条款14
------解决方案--------------------
恩,能详细解释下不?
能说下析构函数是怎么确定Operator Delete()的地址的不?
------解决方案--------------------
基类析构函数没有说明为虚函数,而p是基类指针,所以只执行基类析构函数,输出:Base::destructor.
子类将不会被正确析构掉,造成内存泄露。
------解决方案--------------------
简单点说,出错原因和下面的出错类似:
int *p = new int[10];
delete[](p + 1);
因为基类没有虚拟函数而派生类有虚拟函数的时候,此时基类指针指向派生类对象的时候,会发生this指针偏移,如楼主所举的例子中:
Derived *pd = new Derived;
Base *pb = pd;
可以打印两者的值来看下,应该是不相等的;
在
delete pb;
时,由于基类析构函数不是虚拟函数,所以会首先执行基类的析构函数,然后执行operator delete pb;
这里就会出问题,因为申请的时候返回的值时pd,而pd != pb;
------解决方案--------------------