2013-04-08 82 views
2

我在調用派生類的虛函數時遇到了segfaults的問題。但是,如果我將函數的名稱更改爲與基類中的虛函數的名稱不同,則不會發生這些段錯誤。下面是一些代碼:調用派生類的虛函數時發生Segfault

//in main 
//initialize scene objects 
//camera 
if((camera = (Camera*)malloc(sizeof(Camera))) == NULL){ 
    cout << "Could not allocate memory for camera" << endl; 
} 
//...code in middle 
//inside file parsing... 
//infile is an ifstream 
//nextString is a char* 
if(!strcmp(nextString,"camera")){ 
    camera->parse(infile); //segfault here 
} 

這是基礎類的頭(在.cpp唯一實例變量在構造函數):

class WorldObj{ 
public: 
    WorldObj(); 
    ~WorldObj(); 
    virtual void parse(ifstream&) =0; 
    vec3 loc; //location 
}; 

這裏是我的相機類內部的代碼,我用它來寫虛擬功能:

void Camera::parse(ifstream &infile){ 
    //do parsing stuff 
} 

解析()在頭文件作爲虛擬無效解析(ifstream的&)聲明;

我在這裏的問題是,如果我重新命名解析()內的攝像頭,以類似CameraParse(),並完全忽視的事實是存在要實現的虛擬功能,代碼工作完全沒問題!

您能否介紹一下爲什麼調用虛函數導致段錯誤?我已經與Valgrind進行了檢查,看看是否有任何內存問題,並且它告訴我有8個字節的無效讀/寫。我明白這意味着我沒有爲我的對象分配內存正確,但我不知道我要去哪裏錯分配。

任何幫助,將不勝感激:)

+0

您是*不*調用虛擬從基類的構造函數,是嗎? – dasblinkenlight 2013-04-08 21:00:53

+0

嘗試在Camera類中將解析函數標記爲虛擬以正確方式覆蓋函數 – 2013-04-08 21:04:49

回答

8

你不能(只)malloc非POD對象,你必須new它。

這是因爲malloc保留的空間中的適量,但不構造的對象,這是不平凡的用於與即使構造被默認虛擬函數的任何類。

現在,只有在進行虛擬函數調用時纔會出現特定問題,因爲這取決於new執行的額外初始化,但使用任何非POD類型的未構建實例仍然是錯誤的。


請注意,我用POD(普通舊數據)作爲一個懶惰的簡寫,只有微不足道的初始化什麼。一般而言,一類(或結構)是平凡initializable如果既不它,也沒有任何成員或基類的具有一個構造做一些事情。對於我們而言,與一個或多個虛擬方法每一個類(即使他們繼承,或在數據成員)需要不平凡的初始化。

具體而言,在本福格特的答案的標準報價介紹開頭的對象的生命週期(在此期間,你可以放心地進行方法調用的時候,特別是虛擬的)兩個階段:

  • 存儲與獲得用於類型T適當的對準和尺寸,

其中當調用發生malloc

  • 如果對象具有不平凡的初始化,初始化完成後

發生的非平凡初始化的類型,當您使用new


以供參考,這是你的現有代碼的正常使用最接近:

Camera *camera = new Camera; 
// don't need to check for NULL, this will throw std::bad_alloc if it fails 
camera->parse(file); 
// don't forget to: 
delete camera; 

這是更好的風格,雖然:

std::unique_ptr<Camera> camera(new Camera); 
camera->parse(file); 
// destruction handled for you 

且僅當你真的需要使用malloc或其他特定的分配器:

Camera *camera = (Camera *)malloc(sizeof(*camera)); 
new (camera) Camera; // turn your pointer into a real object 
camera->parse(file); 
// destruction becomes uglier though 
camera->~Camera(); 
free(camera); 
+0

正確...如果他絕對需要與'malloc'兼容他可以寫'camera = new Camera(malloc(sizeof Camera));'但是在大多數情況下只是'camera = new Camera();'是最好的。如果他想繼續使用'NULL'檢查來檢測分配失敗,則使用'std :: nothrow'。 – 2013-04-08 21:02:54

+0

另外,它實際上並不取決於類型是否爲POD,而是初始化是否不平凡。 – 2013-04-08 21:08:40

+0

是的,我傾向於使用POD作爲懶惰的簡寫。 – Useless 2013-04-08 21:17:05

1

使用新的,而不是malloc。您分配了內存,但未創建該對象。 使用new,用相應的構造函數創建虛擬函數調度表,然後才能使用它。例如:

if((camera = new (nothrow) Camera()) == NULL){ 
    cout << "Could not allocate memory for camera" << endl; 
} 

if(!strcmp(nextString,"camera")){ 
    camera->parse(infile); //segfault here 
} 

或者您可以使用簡單的

camera = new Camera; 

而且某處捕捉到更多鈔票的異常bad_alloc的。

+0

'攝像頭'永遠不會'NULL',所以條件是無用的。 – 2013-04-08 21:09:16

+0

@ Ben Voigt。我不是很快的編輯:-(我想給NULL類似的測試方式,但我認爲是好的,或者? – qPCR4vir 2013-04-08 21:31:45

+0

是的,現在你使用了'std :: nothrow'。 – 2013-04-08 22:20:23

1

malloc不調用構造函數。

你必須改變(創建對象的C++的方式)

camera = (Camera*)malloc(sizeof(Camera))) 

camera = new Camera; // Now you camera object will be created and constructed. 
1

無用提供了正確的解釋。這是標準(3.8節)中的要求:

對象的生命週期是對象的運行時屬性。如果一個對象是一個類或聚合類型,並且它的一個成員是由一個不重要的默認構造函數構造函數初始化的,那麼它就被認爲具有不平凡的初始化。 [注意:通過簡單的複製/移動構造函數進行初始化不是簡單的初始化。 - 注完]

T類型的對象的生存期開始時:獲得

  • 存儲有用於T類型的適當對準和尺寸,

  • 如果對象具有非平凡的初始化,其初始化完成。

T類型的對象的生存期結束時:

  • 如果T是一個類類型與非平凡的析構函數,析構函數呼叫開始,或

  • 對象佔用的存儲空間被重用或釋放。

相關問題