2010-01-08 42 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