这个C++测验答案背后的解释是什么?

问题描述:

我在C++ quiz过这个问题(初学C++):我的答案是不正确的,我想知道正确的答案背后的解释 - “未定义行为”这个C++测验答案背后的解释是什么?

问: 后会发生下面的代码是什么函数foo()返回?

class base 
{ 
    public: 
     base() { } 
     ~base() { } 
}; 

class derived : public base 
{ 
    private: 
     int *p_pi_values; 

    public: 
     derived() : p_pi_values(new int[100]) { } 
     ~derived() { delete [] p_pi_values; } 
}; 

void foo(void) 
{ 
    derived *p_derived = new derived(); 
    base *p_base = p_derived; 

    // Do some other stuff here. 

    delete p_base; 
} 

我给了这个答案,结果出错==>整数数组将不会被正确删除。

Correct Answer ==>行为是未定义的。

+0

这可能有助于http://*.com/questions/5392590/destructor-in-c – silvesthu 2012-08-09 22:02:17

你基类的析构函数不是virtual。这只是语言规则,如果通过指向基础子对象的指针删除对象,则相应的基类必须具有虚拟的des,否则它是未定义的行为。 (实际上,如果你的基类没有虚析构函数,编译器可能不会发出必要的代码来执行衍生对象的所有必要的清理工作,它只会假设你的对象是与指针相同的类型,并且不打算进一步查看,因为实际上多数派生对象的多态查找的代价是您不希望施加不必要的代价。)

§5.3.5/ 3:

在第一种替代方法(删除对象)中,如果操作数的静态类型与其动态类型不同pe,静态类型应该是操作数动态类型的基类,而静态类型应该具有虚拟析构函数或行为不明确

+0

一个标准的报价来支持这将是很好的;我最后一次试图在那里查看它,它既不明确也不清楚... – PlasmaHH 2012-08-09 22:08:44

+0

@PlasmaHH它是常识:) – 2012-08-09 22:12:01

+0

@LuchianGrigore:如果是,那么我们需要什么标准呢? – PlasmaHH 2012-08-09 22:12:24

您应该使您的析构函数在基类中变为虚拟。现在代码的问题是delete p_base将导致基类的析构函数被调用。派生类中的一个不会被调用,并且为整数数组分配的内存不会被释放。

发生这种情况是因为如果某个方法在基类中不是虚拟的,编译器只会查看一个指针类型并调用位于此类型中的方法(在这种情况下 - 它是基类),即决定使用哪种方法在编译时根据指针的类型进行调用,而不是指针所指对象的实际类型。

我想编译器可以优化这段代码,因此p_derived从未分配给p_base。

更具体地说,编译器可以将代码优化为一行。

删除new derived();

因此,它被视为未定义的行为可以改变编译器真正优化代码的方式。

+0

这与优化无关。 – 2012-08-09 22:39:01

出于好奇我检查C++规格。问题的答案是第5.3节中的第3项。5:

在第一个替代(删除对象),如果静态类型要被删除的 对象的是二FF erent从它的动态型,静态 类型应是基类的动态类型的的删除对象为 ,静态类型应具有虚拟析构函数或 行为未定义。

就我个人而言,我会以同样的方式回答您的问题。如果你忽略编译器的警告,最可能的结果是派生类的析构函数不会被调用。