使用 std::unique_ptr 时堆已损坏

Heap has been corrupted when using std::unique_ptr

我一直在使用 OpenGL 和 C++ 开发 Quake 3 BSP 加载器。

当我 运行 我的代码时,我 运行 遇到了问题。我遇到了一个问题,它在调试模式下显示 "heap has been corrupted!"。我已经评论了它损坏的那一行。我的评论是'gives me the error at this line "Heap has been corrupted"'

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/vec3.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <vector>   
#include "map.h"
#include <fstream>
#include <memory>
#include "game_manager.h"
#include <thread>

bool KikoBSP::load_map(std::string file_name)
{
    this->file.open(file_name.c_str(), std::ios::in | std::ios::binary);

    if (this->file.is_open())
    {
        this->file.read(reinterpret_cast<char*>(&this->header), sizeof(this->header));

        std::unique_ptr<BSPEntities> ents(new BSPEntities);
        ents->ents_array = new char[this->header.lumps[BSPLUMPS::ENTITIES].length];

        this->num_textures = this->header.lumps[BSPLUMPS::TEXTURES].length / sizeof(BSPTexture);
        this->num_planes = this->header.lumps[BSPLUMPS::PLANES].length / sizeof(BSPPlane);
        this->num_textures = this->header.lumps[BSPLUMPS::TEXTURES].length / sizeof(BSPTexture);
        this->num_nodes = this->header.lumps[BSPLUMPS::NODES].length / sizeof(BSPNode);
        this->num_leafs = this->header.lumps[BSPLUMPS::LEAFS].length / sizeof(BSPLeaf);
        this->num_leaf_faces = this->header.lumps[BSPLUMPS::LEAF_FACES].length / sizeof(BSPLeafFace);
        this->num_leaf_brushes = this->header.lumps[BSPLUMPS::LEAF_BRUSHES].length / sizeof(BSPLeafBrush);
        this->num_models = this->header.lumps[BSPLUMPS::MODELS].length / sizeof(BSPModel);
        this->num_brushes = this->header.lumps[BSPLUMPS::BRUSHES].length / sizeof(BSPBrush);
        this->num_brush_sides = this->header.lumps[BSPLUMPS::BRUSHSIDES].length / sizeof(BSPBrushSides);
        this->num_vertexes = this->header.lumps[BSPLUMPS::VERTEXES].length / sizeof(BSPVerts);
        this->num_meshverts = this->header.lumps[BSPLUMPS::MESHVERTS].length / sizeof(BSPMeshVerts);
        this->num_effects = this->header.lumps[BSPLUMPS::EFFECTS].length / sizeof(BSPEffects);
        this->num_faces = this->header.lumps[BSPLUMPS::FACES].length / sizeof(BSPFaces);

        std::unique_ptr<BSPTexture[]> textures(new BSPTexture[this->num_textures]);
        std::unique_ptr<BSPPlane[]> planes(new BSPPlane[this->num_planes]);
        std::unique_ptr<BSPNode[]> nodes(new BSPNode[this->num_nodes]);
        std::unique_ptr<BSPLeaf[]> leafs(new BSPLeaf[this->num_leafs]);
        std::unique_ptr<BSPLeafFace[]> leaf_faces(new BSPLeafFace[this->num_leaf_faces]);
        std::unique_ptr<BSPLeafBrush[]> leaf_brushes(new BSPLeafBrush[this->num_leaf_brushes]);
        std::unique_ptr<BSPModel[]> models(new BSPModel[this->num_models]);
        std::unique_ptr<BSPBrush[]> brushes(new BSPBrush[this->num_brushes]);
        std::unique_ptr<BSPBrushSides[]> brush_sides(new BSPBrushSides[this->num_brush_sides]);
        std::unique_ptr<BSPVerts[]> vertexes(new BSPVerts[this->num_vertexes]);
        std::unique_ptr<BSPMeshVerts[]> mesh_verts(new BSPMeshVerts[this->num_mesh_verts]);
        std::unique_ptr<BSPEffects[]> effects(new BSPEffects[this->num_effects]);
        std::unique_ptr<BSPFaces[]> faces(new BSPFaces[this->num_faces]);

        this->file.seekg(this->header.lumps[BSPLUMPS::ENTITIES].offset);
        this->file.read(reinterpret_cast<char*>(ents->ents_array), this->header.lumps[BSPLUMPS::ENTITIES].length);

        this->file.seekg(this->header.lumps[BSPLUMPS::TEXTURES].offset);
        this->file.read(reinterpret_cast<char*>(textures.get()), this->header.lumps[BSPLUMPS::TEXTURES].length);

        this->file.seekg(this->header.lumps[BSPLUMPS::PLANES].offset);
        this->file.read(reinterpret_cast<char*>(planes.get()), this->header.lumps[BSPLUMPS::PLANES].length);

        this->file.seekg(this->header.lumps[BSPLUMPS::NODES].offset);
        this->file.read(reinterpret_cast<char*>(nodes.get()), this->header.lumps[BSPLUMPS::NODES].length);

        this->file.seekg(this->header.lumps[BSPLUMPS::LEAFS].offset);
        this->file.read(reinterpret_cast<char*>(leafs.get()), this->header.lumps[BSPLUMPS::LEAFS].length);

        this->file.seekg(this->header.lumps[BSPLUMPS::LEAF_FACES].offset);
        this->file.read(reinterpret_cast<char*>(leaf_faces.get()), this->header.lumps[BSPLUMPS::LEAF_FACES].length);

        this->file.seekg(this->header.lumps[BSPLUMPS::LEAF_BRUSHES].offset);
        this->file.read(reinterpret_cast<char*>(leaf_brushes.get()), this->header.lumps[BSPLUMPS::LEAF_BRUSHES].length);

        this->file.seekg(this->header.lumps[BSPLUMPS::MODELS].offset);
        this->file.read(reinterpret_cast<char*>(models.get()), this->header.lumps[BSPLUMPS::MODELS].length);

        this->file.seekg(this->header.lumps[BSPLUMPS::BRUSHES].offset);
        this->file.read(reinterpret_cast<char*>(brushes.get()), this->header.lumps[BSPLUMPS::BRUSHES].length);

        this->file.seekg(this->header.lumps[BSPLUMPS::BRUSHSIDES].offset);
        this->file.read(reinterpret_cast<char*>(brush_sides.get()), this->header.lumps[BSPLUMPS::BRUSHSIDES].length);

        this->file.seekg(this->header.lumps[BSPLUMPS::VERTEXES].offset);
        this->file.read(reinterpret_cast<char*>(vertexes.get()), this->header.lumps[BSPLUMPS::VERTEXES].length);

        this->file.seekg(this->header.lumps[BSPLUMPS::MESHVERTS].offset);
        this->file.read(reinterpret_cast<char*>(mesh_verts.get()), this->header.lumps[BSPLUMPS::MESHVERTS].length);

        this->file.seekg(this->header.lumps[BSPLUMPS::EFFECTS].offset);
        this->file.read(reinterpret_cast<char*>(effects.get()), this->header.lumps[BSPLUMPS::EFFECTS].length);

        this->file.seekg(this->header.lumps[BSPLUMPS::FACES].offset);
        this->file.read(reinterpret_cast<char*>(faces.get()), this->header.lumps[BSPLUMPS::FACES].length);

        std::printf("BSP VERSION: '%s'\n", this->header.magic);

        if (std::strncmp(this->header.magic, "IBSP", 4) == 0)
        {
            std::printf("SUCCESS: VALID BSP FORMAT!\n");
        }
        else
        {
            std::printf("ERROR: INVALID BSP FORMAT!\n");

            return false;
        }

        std::printf("this->num_of_verts == %i\n", this->num_vertexes);

        for (int32_t x = 0; x <= this->num_vertexes; x++)
        {
            this->vertices.push_back(vertexes.get()[x].position.x);
            this->vertices.push_back(vertexes.get()[x].position.y); /* gives me the error at this line "Heap has been corrupted" */
            this->vertices.push_back(vertexes.get()[x].position.z);

            this->colors.push_back((float)x); /* doesnt follow my code style (using C-style cast), sorry!! I copied this from my old project ;) */
        }

        std::printf("this->vertices.size() == %i\n", this->vertices.size());

        this->shader.load_shader("bsp.vs", "bsp.fs");

        glGenVertexArrays(1, &this->vao);

        glBindVertexArray(this->vao);

        glGenBuffers(1, &this->vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(float), &this->vertices.front(), GL_STATIC_DRAW);

        glGenBuffers(1, &this->color_vbo);
        glBindBuffer(GL_ARRAY_BUFFER, this->color_vbo);
        glBufferData(GL_ARRAY_BUFFER, this->colors.size() * sizeof(float), &this->colors.front(), GL_STATIC_DRAW);

        this->coord3d = glGetAttribLocation(this->shader.program, "coord3d");
        this->mvp = glGetUniformLocation(this->shader.program, "mvp");
        this->attrib_color = glGetAttribLocation(this->shader.program, "v_color");

        glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
        glVertexAttribPointer(this->coord3d, // attribute
            3,                 // number of elements per vertex, here (R,G,B)
            GL_FLOAT,          // the currentBlock of each element
            GL_FALSE,          // take our values as-is
            0,                 // no extra data between each position
            nullptr               // offset of first element
        );

        glBindBuffer(GL_ARRAY_BUFFER, this->color_vbo);
        glVertexAttribPointer(this->attrib_color,
            3,
            GL_FLOAT,
            GL_FALSE,
            0,
            nullptr
        );

        glBindVertexArray(0);

        glVertexAttrib3fv(this->attrib_color, this->colors.data());

        std::printf("size of vector = %i\n", this->vertices.size());

        return true;
    }
    else
    {
        std::printf("ERROR: COULDN'T OPEN FILE!\n");

        return false;
    }

    return false;
}


void KikoBSP::render(glm::vec3 position)
{
    glBindVertexArray(this->vao);
    glEnableVertexAttribArray(this->coord3d);
    glEnableVertexAttribArray(this->attrib_color);

    glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(position.x, position.y, position.z));
    glm::mat4 mvp = game_manager->projection * game_manager->view * model;
    glUniformMatrix4fv(this->mvp, 1, GL_FALSE, glm::value_ptr(mvp));

    glDrawArrays(GL_LINES, 0, this->vertices.size());

    glDisableVertexAttribArray(this->coord3d);
    glDisableVertexAttribArray(this->attrib_color);
    glBindVertexArray(0);
}

void KikoBSP::cleanup_map()
{
    /* OUTDATED FUNCTION BACK WHEN I WAS MANUALLY MANAGING MEMORY */
}

但是,当我删除这些行时,错误消失了:

    this->file.seekg(this->header.lumps[BSPLUMPS::EFFECTS].offset);
    this->file.read(reinterpret_cast<char*>(effects.get()), this->header.lumps[BSPLUMPS::EFFECTS].length);

    this->file.seekg(this->header.lumps[BSPLUMPS::FACES].offset);
    this->file.read(reinterpret_cast<char*>(faces.get()), this->header.lumps[BSPLUMPS::FACES].length);

这让我相信堆溢出了所有分配的内存。 我也相信这一点,因为当我手动管理内存时。我 运行 也遇到了同样的问题。所以我切换到 unique_ptrs,但我仍然遇到同样的问题! :(

这里有人有什么想法吗?谢谢! :)

你的循环条件不正确:

for (int32_t x = 0; x <= this->num_vertexes; x++)

在其最后一次迭代中 x == num_vertexes,这意味着您正在尝试读取超出数组边界的值。检查调试器 - 你会看到当堆损坏发生时 x 取这个值。另外,我很确定这不是您标记为导致堆损坏的行,而是之前的行 - 许多调试器显示要执行的下一行,而不是正在执行的行。

顺便说一句,我不熟悉您使用的 类,因此不能确定,但​​您很可能在滥用 std::unique_ptr。只需使用 std::vector 而不是指向动态数组的唯一指针 - 它更简单、更易于使用并且应该完全按照您期望的方式工作。