2010-01-08 36 views
2

每幀我需要分配一些需要堅持的數據直到幀結束。C++垃圾收集和調用析構函數

目前,我從一個不同的內存池中分配數據,允許我用幀數對它進行標記。在幀的末尾,我遍歷內存池並刪除在特定幀中分配的內存。

我遇到的問題是,爲了保持保持上的數據,我必須把它正是如此的結構:

struct FrameMemory 
{ 
    uint32 frameIndex; 
    bool allocatedType; //0 = new(), 1 = new[] 
    void* pMemPtr; 
} 

所以後來,當我得到周圍的釋放內存,它看起來是這樣的:

{ 
for(all blocks) 
if(block[i].frameIndex == targetIndex) 
    if(block[i].allocatedType == 0) 
      delete block[i].pMemPtr; 
    else if (block[i].allocatedType ==1) 
      delete[] block[i].pMemPtr; 
} 

的問題是,因爲我有超載的指針內存作爲一個void *,delete運算符不正確地刪除存儲作爲其本土基地類型。 IE的析構函數從不會被調用該對象。

我試圖找到方法來使用智能指針模板對象的解決方案,但爲了做到這一點,我不得不將模板類重載到非模板化基類型,這使得刪除更多難。

有沒有人有這樣的問題的解決方案?

+1

你能提供一些你的問題背景嗎?你在編寫一個編譯器嗎? 'frame'是什麼意思? – 2010-01-08 15:32:41

+0

按幀我的意思是一個處理框架。就像在遊戲中一樣,或者模擬以每秒30幀的速度運行。 – ddigit 2010-01-08 15:35:38

+0

在垃圾收集器中存儲void *的一個大問題是,當您刪除內存時,您將不會調用該對象的析構函數。你只需要釋放內存。如果對象擁有任何資源(或持有鎖等),則這些資源將泄漏。你需要做一些像月亮暗示的事情。 – 2010-01-08 16:02:24

回答

6

如果你不想強迫所有的物體從Destructible繼承,你可以存儲指向一個刪除函數(或函子)以及指向數據本身的指針。客戶端代碼負責提供,知道如何正確地刪除數據,通常類似的功能:

void xxx_deleter(void *data) { 
    xxx *ptr = static_cast<xxx *>(data); 
    delete ptr; 
} 

雖然缺失者將通常是很多像上面的,這也給客戶端的選項存儲複雜的數據結構,並仍然正確地刪除它們。

+0

這種方法將工作得很好。它允許正確調用析構函數,並允許爲基類型生成默認的析構函數。這允許我不必使用基類來重載所有內容,並防止我管理多個池。謝謝。 – ddigit 2010-01-08 16:08:32

+0

這與boost :: shared_ptr採用的方法類似。如果你感覺冒險,你可能想看看它的實現,因爲有幾個角落的情況下,要妥善處理。 http://www.boost.org/doc/libs/1_41_0/libs/smart_ptr/shared_ptr.htm – 2010-01-08 17:30:10

6
class Destructable 
{ 
public: 
    virtual ~Destructable() {} 
}; 

而不是void *,在池中存儲Destructable *。使從池中分配的對象從Destructable繼承。

或者,覆蓋相關類的運算符newdelete。讓他們使用游泳池。一旦CPU完成了對象的刪除操作,就會以常規方式在擁有它的代碼中刪除對象,並因此知道它的正確類型;因爲池在看到適當的幀結束之前不會重用內存,不管異步硬件如何以這種方式滯後垃圾回收仍然可以做到這一點。

+0

問題在於,它使得難以從池中分配不繼承該基本類型的類型。例如,如果我想從池中分配一個Ints數組,除非我爲它創建了一個新的包裝器,否則我不能再這麼做。 – ddigit 2010-01-08 15:40:54

+3

然後,你將不得不創建一個包裝。或者爲該類型使用單獨的池。池本身可以是一個類模板來包含你需要的任何類型的對象。 C++是一種靜態類型語言。試圖強制它像一個動態類型的語言是一個壞主意。我知道,因爲我已經嘗試過了。 :) – Dima 2010-01-08 15:49:11

+0

這種方法的另一個問題是,它強制課程是虛擬的,否則他們不需要。 – keraba 2010-01-09 14:43:21

0

我能想到的唯一方法就是將一個類型入口添加到FrameMemory結構中,然後使用它來正確地轉換內存以進行刪除。舉例來說,如果你有Foo類型的內存,你可以有這樣的:

if (block[i].BlockType == BLOCKTYPE_FOO) 
{ 
    foo *theMemory = (foo *)block[i].pMemPtr; 

    delete theMemory; 
} 

請注意,這可能是一個非常**** ****如果你這樣做是錯誤的危險操作。

0

如果你是平均棧幀(即內部功能) 你可以嘗試使用了alloca()

0

我能想到的第一件事情就是使用boost::shared_ptr<void>(對於非數組版本,可能需要一些工作以使其適用於陣列版本)作爲指針類型。我認爲這應該主要關注每個細節。每當幀被破壞的內存將被適當地刪除:

struct FrameMemory 
{ 
    uint32 frameIndex; 
// bool allocatedType; //0 = new(), 1 = new[] only works with instances, not arrays 
    boost::shared_ptr<void> pMemPtr; 
}; 

如果你想手動實現類似的東西,你可以用一個「刪除器」函數指針來處理對象的刪除,而不是直接調用delete 。這是一個粗略的辦法,你可以如何修改代碼:

// helper deleter functions 
template <typename T> 
void object_deleter(void *p) { 
    delete static_cast<T*>(p); 
} 
template <typename T> 
void array_deleter(void *p) { 
    delete [] static_cast<T*>(p); 
} 

class FrameMemory 
{ 
public: 
    const uint32 frameIndex; 
    void* pMemPtr; 
private: 
    void (*deleter)(void*); 
public: 
    template <typename T> 
    FrameMemory(uint32 frame, T* memory, bool isarray = false) 
     : frameIndex(frame), pMemPtr(memory), 
     deleter(isarray? array_deleter<T> : object_deleter<T>) 
    {} 
    void delete() { 
     deleter(pMemPtr) 
    } 
}; 
struct X; 
void usage() 
{ 
    { 
     FrameMemory f(1, new X); 
     f.delete(); 
    } 
    { 
     FrameMemory f(1, new x[10], true); 
     f.delete(); 
    } 
} 

我會進一步修改,以便而不必調用在析構函數執行FrameMemory::delete(),但會採取比我有權更多的時間現在做正確(即決定如何副本都被處理等等...

0

我會做這樣的事情:

struct FrameMemoryBase 
{ 
    uint32 frameIndex; 
    bool allocatedType; //0 = new(), 1 = new[] 
    virtual void Free() = 0; 
}; 

template <typename T> 
struct FrameMemory : public FrameMemoryBase 
{ 
    void Free() 
    { 
    if(allocatedType == 0) 
     delete pMemPtr; 
    else if (allocatedType ==1) 
     delete[] pMemPtr; 
    } 

    T *pMemPtr; 
}; 

,您將通過使用:

{ 
for(all blocks) 
    if(block[i].frameIndex == targetIndex) 
     block[i].Free(); 
}  

如果您還可以釋放FrameMemory結構,則可以將Free更改爲虛擬析構函數。我不確定這是你在找什麼,因爲我不明白「我試圖找到方法來爲解決方案使用智能指針模板對象,但爲了做到這一點,我必須重載模板化類到非模板化基類型,這使得刪除更加困難。「意味着,但我希望這是有幫助的。

這需要內存管理代碼以某種方式訪問​​您希望釋放的內容的聲明,但我不認爲有任何解決方法,假設您需要調用析構函數,您明確要這樣做。

+0

嗯......我寫這篇文章的時候一點也不考慮。我假設你保留了一系列的塊。我開始考慮如何修改我的答案,使之成爲可能,並且實現了dribeas已經提供的答案。 – Edward 2010-01-08 20:24:33