我怎样才能解决这个问题? “正常块后检测到堆损坏。CRT 检测到应用程序在堆缓冲区结束后写入内存”

How can I fix this? " HEAP CORRUPTION DETECTED after normal block.. CRT detected that the application wrote to memory after end of heap buffer "

我有一个程序使用引用运行良好(没有提示错误),但我决定使用分配在虚拟内存上的指针到指针数组,因为我可以使用变量作为数组的大小。

当我打破 while (m_Window.isOpen()) 循环时出现错误提示,换句话说当我关闭游戏 window 并且游戏结束时。我注意到当我尝试在 Engine::cleanVirtualMemory() 函数中擦除虚拟内存时程序中断了。我注意到它在那里,因为我放了两个标志(cout << "running1" << endl;cout << "running2" << endl),我只能显示第一个标志。

然后它会提示 window 并显示以下消息:

HEAP CORRUPTION DETECTED after normal block.. CRT detected that the application wrote to memory after end of heap buffer

main.cpp

#include "Engine.h"
using namespace sf;

int main(){

    Engine Motor;
    Motor.run();
    Motor.cleanVirtualMemory();
}

Engine.h

#pragma once
#include <SFML/Graphics.hpp>
#include "StructureBuilder.h"

using namespace sf;
using namespace std;

class Engine{
private:

    // Lots of variables ....
    Vector2i m_ArenaSize;
    Vector2f * vectorStructureArray = new Vector2f[m_ArenaSize.y * m_ArenaSize.x * 4];
    int** logicStructureArray = new int*[m_ArenaSize.y];
    // Lots of variables ....

    //Gameloop
    void Input();
    void Update(dtAsSeconds);
    void Draw();

public:

    Engine();
    void run();
    void cleanVirtualMemory();

};

Engine.cpp

#include "Engine.h"
#include <iostream>

using namespace sf;


Engine::Engine() {

/// lots of variables and data ...

/// Making arena
m_ArenaSize = Vector2i(10, 10);
StructureBuilder(arenaStructures, vectorStructureArray, logicStructureArray,  m_ArenaSize);
}


void Engine::run() {

//Timing
Clock clock;
while (m_Window.isOpen()) {

    // Each time clock restarted, dt = time elapse (from 0 to now, then clock = 0)
    Time dt = clock.restart();

    // Convert time elapse to seconds
    double dtAsSeconds = dt.asSeconds();
   
    //  Call each part of the game in turn
    Input();
    Update(dtAsSeconds);
    Draw();
    }
}

void Engine::cleanVirtualMemory() {
    // Deallocate Virtual Memory
    
    // first flag
    cout << "running1" << endl;

    for (int i = m_ArenaSize.x - 1; i > -1; i--) {
        delete[] logicStructureArray[i];
    }
    delete[] logicStructureArray;
    logicStructureArray = NULL;
    delete[] vectorStructureArray;
    vectorStructureArray = NULL;

   // second flag
   cout << "running2" << endl;
}

StructureBuilder.h

#pragma once
#include <SFML/Graphics.hpp>
#include <iostream>
#include <string.h>

using namespace sf;
using namespace std;

Vector2i StructureBuilder(VertexArray& rVA, Vector2f* rA, int** rLA, Vector2i ArenaSize);

在下面的代码中,您可以看到我在哪里使用了指针,为了简化,我删除了代码。

StructureBuilder.cpp

#include "StructureBuilder.h"

Vector2i StructureBuilder(VertexArray& rVA, Vector2f* rA, int** rLA, Vector2i ArenaSize) {

    //Set map properties and VertexArrayType
    double tileSize = 100;
    double Height = ArenaSize.y * tileSize;
    double angle = 30;
    int offset = 0;
    int Primitive = 4;
    int currentVertex = 0;

    rVA.setPrimitiveType(Quads);
    rVA.resize(ArenaSize.x * ArenaSize.y * 4);

    // First build graphically our map structures's using char strings 
    string stringArray[10]; 
    stringArray[0] = "1000000000";
    stringArray[1] = "0000000000";
    stringArray[2] = "0000010000";
    stringArray[3] = "0000000000";
    stringArray[4] = "0000000000";
    stringArray[5] = "0000000000";
    stringArray[6] = "0000000000";
    stringArray[7] = "0000000000";
    stringArray[8] = "0000000000";
    stringArray[9] = "0000000000";

    // Convert stringArray to charArray, finally charArray to intArray
    char** charArray = new char*[ArenaSize.y]; 

    Vector2f Vector1;
    Vector2f Vector2;
    Vector2f Vector3;
    Vector2f Vector4;

    for (int i = 0; i < ArenaSize.x; i++) {
       charArray[i] = new char[ArenaSize.x];
       rLA[i] = new int[ArenaSize.x];
        
    }

    for (int i = 0; i < ArenaSize.x; i++) {
        for (int j = 0; j < ArenaSize.y; j++) {
            charArray[j][i] = stringArray[j][i];
            rLA[j][i] = charArray[j][i] - 48;

            // Check when we have a value greater or equal to 1, if yes build a structure.
            if (rLA[j][i] == 1) {

                
                Vector1 = Vector2f(Value..., Value...);// in order to understand I dont put the whole calculation here
                Vector2 = Vector2f(Value..., Value ...); // is just trigonometry to find vertex
                Vector3 = Vector2f(Value..., Value ...);
                Vector4 = Vector2f(Value..., Value ...);


                rVA[currentVertex + 0].position = Vector1;
                rVA[currentVertex + 1].position = Vector2;
                rVA[currentVertex + 2].position = Vector3;
                rVA[currentVertex + 3].position = Vector4;

                rVA[currentVertex + 0].texCoords = Vector2f(42, 0); // coords on my spritesheet
                rVA[currentVertex + 1].texCoords = Vector2f(86, 24);
                rVA[currentVertex + 2].texCoords = Vector2f(42, 49);
                rVA[currentVertex + 3].texCoords = Vector2f(0, 24);

                rA[currentVertex + 0] = Vector1; //Later I use this to tell the program where to construct restrictions (where the player can't move)
                rA[currentVertex + 1] = Vector2;
                rA[currentVertex + 2] = Vector3;
                rA[currentVertex + 3] = Vector4;
            }
           
            currentVertex = currentVertex + Primitive;
        }
    }

    // Deallocate Virtual Memory
    for (int i = ArenaSize.x - 1; i > -1; i--) {
        delete[] charArray[i];
    }
    delete[] charArray;
    charArray = NULL;


    return ArenaSize;
}

我们来看看Engineclass.

的声明
class Engine{
private:

    // Lots of variables ....
    Vector2i m_ArenaSize;
    Vector2f * vectorStructureArray = new Vector2f[m_ArenaSize.y * m_ArenaSize.x * 4];

Engine class 的第一个成员叫 m_ArenaSize。这是在构造 Engine 时构造的第一个 class 成员。这就是 C++ 中对象构造的工作方式:构造新对象时,新对象的所有成员都按声明顺序构造。

您的 Engine class 的第二个成员是这个 vectorStructureArray 指针。它将被分配指向一个数组,具有动态大小,使用 m_ArenaSize 自己构造的两个成员 xy 得到 newed。 =53=]

现在,让我们看一下 Engine 的构造函数:

Engine::Engine() {

好的。那是你的构造函数。所以,根据我们的计划,m_ArenaSize 将得到 default-constructed,因为它没有显式构造,在 Engine 的构造函数的初始化部分(这里有 none) .如果您调查 m_ArenaSize 的默认构造函数,您会发现它默认 xy 为 0.

这就是构造 vectorStructureArray 指针的原因,作为 Engine 默认初始化的第二个业务顺序。并且,因为它的 xy 是 0,所以指针将指向总共 0 个值。

m_ArenaSize = Vector2i(10, 10);

现在 default-constructed m_ArenaSize 被替换为不同的主题,具有不同的 xy 值。显示的代码显然希望指针重新分配,以反映 m_ArenaSize 的新 xy 值。但是 C++ 不是这样工作的。 vectorStructureArray 已经建成。它不会仅仅因为替换了一个不同的 class 成员而再次构造。后续代码的假设是新的 xy 值,这会导致相当明显的内存损坏。

logicStructureArray 也出现了同样的错误。

这些只是所示代码中有关内存分配的前两个主要错误。修复错误的方法有多种,但修复错误最简单的方法是从一开始就让错误在逻辑上不可能发生。如果从未使用过 newdelete 相关的错误,在逻辑上是不可能发生的。现代 C++ 代码很少使用 newdelete,而是使用 C++ 库的许多容器的服务。

这里,两个指针都可以简单地替换为 std::vector,其 resize() 成员负责分配两个向量的大小。而且,作为额外的奖励,所有分配的内存都会自动释放,自动防止所有内存泄漏。

将所有 error-prone newdelete 逻辑替换为 std::vector 将解决显示代码中的所有 memory-related 问题,您唯一要做的就是必须确保向量正确 resize()d.