C++通過基類指針delete派生類數組,析構函數是虛函數,程序為什麼會崩潰?

代碼如下

#include&
using namespace std;

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

class derived:public base{
int a;
};

int main(){
base *p=new derived[10];
delete[] p;
return 0;
}


在某些實現里,base4個位元組,derived8個位元組,你new了一個80個位元組的derived*數組然後當base*幹掉,那麼要麼它就會執行析構函數20次然而有10個this指針式不對的,要麼他會執行10次然而有5個this指針是不對的。自然要掛。

然而在VC++下面卻沒問題,因為VC++的實現是記錄了array的個數和每個對象的大小,他不會因為你把數組搞成了base*就真的以為他是base[],所以會執行10次析構函數,10次的this指針都對。

為什麼錯誤的this指針就會掛呢?因為從base調用derived::~derived函數的方法,是先把一個固定的數字加到this指針上面得到一個全局的代表derived在base上面的虛函數表,然後再虛函數表裡面找到析構函數的指針,最後執行它。如果你的this有問題,那中間有一步就會dereference失敗,自然AV。


c++ 03 5.3.5

In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the operand』s dynamic type and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.


More Effective C++

Item 3: Never treat arrays polymorphically.


簡單說,儘管derive is-a base,但是derive[] is-not-a base[]。

就醬。


MAC下g++編譯不會崩潰。

這種寫法,不支持多態,delete[]時只有~base()被調用。


http://debian.fmi.uni-sofia.bg/~mrpaff/Effective%20C++/MEC/MI3_FR.HTM


「C++的數組不支持多態」?

我只是搬運工~

ZZ FROM 耗子


數組裡面存指針就行了


C++ 對數組執行++時,根據的是數組類型與初始地址。例如你的派生類大小是8個位元組,而基類是4個位元組。當你的指針base ptr++ 時,它只會挪動4個位元組,這顯然和你的預期是不同的,所以指針移動到了錯誤的地方,於是,delete也就出錯了。


推薦閱讀:

面向對象和面向過程的區別有哪些?
面向對象程序設計比傳統的面向過程程序設計更有什麼好處?
面向對象編程是否是從根本上反模塊化且反並行的?為什麼?
面向對象編程的弊端是什麼?

TAG:編程 | 面向對象編程 | C |