删除在堆上存储数据的堆中的对象

我的程序是使用SDL库中的类编写的。

我有以下课程:

class s_group
{
    private:
        SDL_Surface* image;
        unsigned int* F_total;
        float* F_length;
        SDL_Rect** F;
        float* F_current;
        unsigned int S_total;
        unsigned int S_current;

    public:
        s_group(void);
        virtual ~s_group(void);

        bool setup( const char* filename, unsigned int s );
        //other member functions
};

私有成员指针每个存储在堆上声明的内存位置,由成员函数setup分配。

bool s_group::setup( const char* filename, unsigned int s )
{
    s_group::~s_group();//delete already allocated heap memory
    if(!load_file(image, filename))
    {
        image = NULL;
        return false; 
    }

    S_total = s;
    F = new SDL_Rect*[S_total];
    F_total = new unsigned int[S_total];
    F_length = new float[S_total];
    F_current = new float[S_total];

    for(unsigned int index = 0; index < S_total; ++index)
    {
        F[index] = NULL;
        F_total[index] = 0;
        F_length[index] = 0.f;
        F_current[index] = 0.f;
    }
    //loop for each array slot and set values of data
    return true;
}

在一个大函数中,我在堆上创建了这个类的一个对象,将其地址存储在一个名为sparkles_group指针中。

s_group* sparkle = new s_group;
sparkle->setup("sparkle_final.png", 1 );

完成该函数后,我调用delete来重新分配堆内存。 删除这条线解决了这个问题,然而这会导致内存泄漏。

delete sparkle; 
sparkle = NULL;

这将调用该类的析构函数,这是我认为由于内部使用delete操作符而发生错误的地方。

s_group::~s_group(void)
{
    SDL_FreeSurface(image);
    image = NULL;

    for(unsigned int s = 0; s < S_total; ++s)
    {
        for(unsigned int f = 0; f < F_total[s]; ++f)
        {
            F[s][f].x = 0; 
            F[s][f].y = 0;
            F[s][f].w = 0; 
            F[s][f].h = 0;
        }
        delete[] F[s]; 
        F[s] = NULL;
    }
    delete[] F; 
    F = NULL;

    delete[] F_total; 
    F_total = NULL;

    delete[] F_length; 
    F_length = NULL;

    delete[] F_current; 
    F_current = NULL;

    S_total = 0;
    S_current = 0;
}

到达删除操作员时,会出现一个对话框,指出:

Windows已经在Program.exe中触发了一个断点。 这可能是由于堆的损坏,这表明Program.exe或它已加载的任何DLL中存在一个错误。

如何在不导致堆损坏的情况下delete此对象?


来自有效的C ++ Scott Meyers

第9项:在施工或销毁期间切勿调用虚拟功能。

在施工或销毁期间,你不应该调用虚函数,因为这些调用不会做你的想法,如果他们这样做,你仍然会不高兴。 如果您是恢复Java或C#程序员,请密切关注此项目,因为这是一种使用C ++ zags的语言缩写的地方。

实际上,即使你应该定义你的析构函数,强行调用它应该是不可能的


我无法编译你的代码,但在这里..

我注意到的第一件事就是你叫你的析构函数。你不想这么做! 相反,创建一个释放函数并调用它。

我注意到的下一件事是类本身没有FRAME变量..所以这一行:

FRAME = new SDL_Rect*[S_total];

会导致编译错误,并且你的析构函数使用FRAME但不存在这样的变量。 我想你的意思是把它改为F因为如果不是的话,那么这一行:

F[index] = NULL;

是未定义的行为,因为F是未初始化的..

此外,您从未初始化FRAME每个索引,因此在析构函数中访问它,如:

FRAME[s][f].x = 0;

是一个禁忌。

再次,你打电话

delete[] F; 
F = NULL;

但F没有分配内存并且未初始化。

因此,我认为所有的补丁:

class s_group
{
    private:
        SDL_Surface* image;
        unsigned int* F_total;
        float* F_length;
        SDL_Rect** FRAME;
        float* F_current;
        unsigned int S_total;
        unsigned int S_current;

        void Release();

    public:
        s_group(void);
        virtual ~s_group(void);

        bool setup(const char* filename, unsigned int s);
        //other member functions
};


bool s_group::setup(const char* filename, unsigned int s)
{
    Release();//delete already allocated heap memory

    if(!load_file(image, filename))
    {
        image = NULL;
        return false; 
    }

    S_total = s;
    FRAME = new SDL_Rect*[S_total];
    F_total = new unsigned int[S_total];
    F_length = new float[S_total];
    F_current = new float[S_total];

    for(unsigned int index = 0; index < S_total; ++index)
    {
        FRAME[index] = NULL;
        F_total[index] = 0;
        F_length[index] = 0.f;
        F_current[index] = 0.f;
    }
    //loop for each array slot and set values of data
    return true;
}

void s_group::Release()
{
    SDL_FreeSurface(image);
    image = NULL;

    for(unsigned int s = 0; s < S_total; ++s)
    {
        for(unsigned int f = 0; f < F_total[s]; ++f)
        {
            if (FRAME[s])
            {
                FRAME[s][f].x = 0; 
                FRAME[s][f].y = 0;
                FRAME[s][f].w = 0; 
                FRAME[s][f].h = 0;
            }
        }
        delete[] FRAME[s]; 
        FRAME[s] = NULL;
    }
    delete[] FRAME; 
    FRAME = NULL;

    delete[] F_total; 
    F_total = NULL;

    delete[] F_length; 
    F_length = NULL;

    delete[] F_current; 
    F_current = NULL;

    S_total = 0;
    S_current = 0;
}

s_group::~s_group(void)
{
    Release();
}

应该这样做..只是不要忘记为FRAME[index]分配内存我不知道多少或你想分配什么,所以我改变了Release功能,以检查FRAME[index]是否有效与if-statement

我强烈建议您使用一些SmartPointers并忘记自己处理每一个内存分配。


自发布这个问题以来,我找到了错误的来源并解决了问题。 在为动态2D数组设置数据值的单独代码段中,循环验证不正确。

for( unsigned int index = 0; index <= F_total[ S_current ]; ++index ) {  
    //set data values for each slot in the array
    F[ S_current ][ index ].x = 0; etc...
}

可以看出,循环显然会尝试修改等于创建数组大小的位置。 当然,注意到数组从索引0开始,因此最终的插槽将大小为-1。写代码时我错过了一些非常愚蠢的事情。 实际循环:

for( unsigned int index = 0; index < F_total[ S_current ]; ++index ) {  
    //set data values for each slot in the array
    F[ S_current ][ index ].x = 0; etc...
}

给任何尝试自己的内存管理的人的消息:

  • 寻找堆腐败的来源是很困难的,因为编译器会在错误代码段中找到不一定会导致问题的代码。
  • 问题的原因将只存在于影响内存的代码部分。 确保您不会尝试访问或更糟地修改您未提供的任何内存。
  • 我仍然相信内存管理是一种很好的学习方式,并且比使用容器或智能指针更适合以这种方式完成任何项目。 这是我个人的偏好,尽管定制内存管理通常只提供很少的优势,只有复杂性。
  • 在寻求帮助时,请提供有关该问题的所有相关代码。 虽然编译器可能会在一节中指导您解决问题,但正如我之前所说的,堆损坏并不一定就存在。
  • 链接地址: http://www.djcxy.com/p/82879.html

    上一篇: Deleting objects on the heap which store data on the heap

    下一篇: An object in heap riddle