在对象不再存在后,如何销毁与对象关联的数据?

时间:2009-07-07 23:34:38

标签: c++ opengl graphics

我正在创建一个类(比方说,C),它将数据(比方说,D)与一个对象(比如说O)联系起来。当O被破坏时,O会通知C它很快将不复存在:( ......之后,当C感觉到它是正确的时候,C将放弃属于O的东西,即D。

如果D可以是任何类型的对象,那么C能够执行“删除D”的最佳方式是什么?如果D是一个对象数组怎么办?

我的解决方案是让D派生自C知道的基类。到时候,C调用删除指向基类的指针。

我还考虑过存储void指针并调用delete,但我发现这是未定义的行为并且不会调用D的析构函数。我认为模板可能是一个新颖的解决方案,但我无法解决这个问题。

这是我到目前为止的C,减去一些细节:


// This class is C in the above description. There may be many instances of C.
class Context
{
public:
    // D will inherit from this class
    class Data
    {
    public:
        virtual ~Data() {}
    };

    Context();
    ~Context();

    // Associates an owner (O) with its data (D)
    void add(const void* owner, Data* data);

    // O calls this when he knows its the end (O's destructor).
    // All instances of C are now aware that O is gone and its time to get rid
    // of all associated instances of D.
    static void purge (const void* owner);

    // This is called periodically in the application. It checks whether
    // O has called purge, and calls "delete D;"
    void refresh();

    // Side note: sometimes O needs access to D
    Data *get (const void *owner);

private:
    // Used for mapping owners (O) to data (D)
    std::map _data;
};

// Here's an example of O
class Mesh
{
public:
    ~Mesh()
    {
        Context::purge(this);
    }

    void init(Context& c) const
    {
        Data* data = new Data;

        // GL initialization here

        c.add(this, new Data);
    }

    void render(Context& c) const
    {
        Data* data = c.get(this);
    }

private:
    // And here's an example of D
    struct Data : public Context::Data 
    {
        ~Data()
        {
            glDeleteBuffers(1, &vbo);
            glDeleteTextures(1, &texture);
        }

        GLint vbo;
        GLint texture;
    };
};

P.S。如果您熟悉计算机图形和VR,我正在创建一个类,它将对象的每个上下文数据(例如OpenGL VBO ID)与其每个应用程序数据(例如顶点数组)分开,并释放每个上下文适当时间的数据(当匹配的渲染上下文是当前的时候)。

3 个答案:

答案 0 :(得分:1)

您正在寻找的是Boost::shared_ptr,或类似的智能指针系统。

答案 1 :(得分:1)

问题在于要求相当模糊,所以很难给出一个好的具体答案。我希望以下有所帮助。

如果您希望数据在其所有者死亡时立即消失,请让所有者删除它(如果C实例需要知道则通知C)。如果您希望C在闲暇时进行删除,您的解决方案看起来很好。在我看来,从数据中获取是正确的。 (当然,正如你所做的那样,~Data()必须是虚拟的。)

如果D是一个对象数组怎么办?这个问题有两种解释。如果你的意思是D总是一个数组,那就让它成为指向Data的指针的数组(或矢量<>)。然后在C :: purge()中走向量并删除对象。如果你的意思是D可以是一个对象数组但也可以是一个对象,那么有两种方法可以去。要么决定它总是一个数组(可能大小为1),要么它是一个单个对象(从Data派生),它可以是一个包装实际对象数组(或指向它们的指针)的类。在后一种情况下,包装类析构函数应该遍历数组并执行删除操作。请注意,如果您希望数组(或向量<>)包含实际对象,而不是指向它们的指针(在这种情况下您不必走数组并手动删除),那么您将具有以下限制。 1.数组中的所有对象必须具有相同的实际类型。 2.您必须将数组声明为该类型。这将失去你对多态性的所有好处。

答案 2 :(得分:0)

要回答这个问题,“如果D是一个对象数组怎么办?”,我建议使用一个矢量<>,但你必须将它与D关联起来:

struct D_vector
    :D
{
    vector<whatever> vw;
};