2012-10-25 94 views
1

我不確定下面的代碼是否從內存泄漏中安全。多態C++與純虛函數析構函數

#ifndef RENDERABLE_H 
#define RENDERABLE_H 

class QGLShaderProgram; 
class GLWidget; 
class BoundingBox; 

class Renderable{ 

public: 
    virtual void update(float duration) = 0; 
    virtual void render(QGLShaderProgram& shader, float duration) = 0; 
    virtual BoundingBox* getBBox() const = 0; 
    virtual void translate(float xx, float yy, float zz) = 0; 
    virtual void rotate(float degrees_x, float degrees_y, float degrees_z) = 0; 
    virtual void scale(float xx, float yy, float zz) = 0; 
}; 

#endif // RENDERABLE_H 

上述「接口」由object3d.cpp實現。然後,如果它們屬於同一個場景,我們可以將許多Object3D對象添加到一個Scene對象中。但是,在場景結束時,我想確保沒有內存泄漏,因此我會在所有內容上調用delete。然而,在場景的對象,我有以下變量:

QVector<Renderable*>* sceneObjects; 
QVector<GLTexture2D*>* sceneTextures; 
QMap<QString, Material*>* sceneMaterials; 

正如你所看到的,

delete sceneObjects; 
delete sceneTextures; 
delete sceneMaterials; 

應該刪除QVector並根據Qt的,它應該調用這些對象的析構函數它。但是,Qt文檔並不清楚對象指針。 Qt會刪除它們正確的析構函數的對象指針嗎?另外,可Renderable指針會發生什麼?正如你可以從「界面」看到的那樣,它沒有析構函數。

感謝您的任何意見。 ChaoSXDemon

回答

5

首先,您的Renderable類必須具有虛擬析構函數,因爲調用delete上的基指向派生對象的指針是未定義的行爲而沒有一個。

其次,不,你將需要遍歷並在每個指針調用delete(或as Nikos noted,使用qDeleteAll只要容器裏的每對象與普通new(而不是new[]malloc或任何分配),以確保它們的內存被回收(Qt如何知道指針是否指向由new分配的東西?他們可以指向由new[]分配的東西,堆中的東西,堆棧或其他地方)。

如果你不想這樣做,你可以存儲unique_ptr S IN的容器,然後unique_ptr S的析構函數將被調用時,你delete的容器,和那些析構函數會收回他們擁有的內存。無需手動釋放它們或使用qDeleteAll

+0

所以我想析構函數也必須是純虛擬的? – ChaoSXDemon

+0

@ChaoSXDemon不是純虛擬的,只是虛擬的。你可以把它變成純粹的虛擬,但沒有任何意義,它必須有一個定義。 –

+0

我應該在我的實現對象中寫入什麼內容,以便對於使用Renderable的w/e對象,它會調用正確的去desturctor? – ChaoSXDemon

2

您需要手動刪除每個指針。你不需要手動遍歷每一個。你可以很容易地做到這一點:

qDeleteAll(*sceneObjects); 
delete sceneObjects; 

您的其他容器相同。 qDeleteAll記錄在此處:http://doc.qt.digia.com/qt/qtalgorithms.html#qDeleteAll-2

還要添加一個虛擬dtor,如Seth Carnegie所述。

+0

謝謝,它現在工作正常。但是,QVector似乎找不到我的物品。假設我有:Renderable * o1 = new Object3D()和後來我調用(在rItems.append(o1)之後),rItems.remove(rItems.indexOf(o1))它給我索引數組越界。具體來說,返回的索引是-1。任何想法爲什麼? – ChaoSXDemon

+0

@ChaoSXDemon indexOf()在找不到元素時返回-1。這是它告訴你「找不到」的唯一方法。 (請記住,Qt不使用異常處理。)你不應該只用它的返回值作爲索引;首先檢查「<0」。 –