【问题标题】:SIGSEGV Segmentation Fault when dereferencing a pointer取消引用指针时出现 SIGSEGV 分段错误
【发布时间】:2021-10-24 18:54:14
【问题描述】:

我知道已经有几个与此类似的问题,但我已经阅读了它们,但似乎没有一个能涵盖我的具体问题......

我正在尝试从结构中取消引用公共指针,但它会引发 SIGSEV 分段错误,即使指针确实指向一个值

它会打印 1 和 2,但不会进一步。如果我将其更改为引用指针而不是值,则错误会移动到我引用该值的任何位置,因此我知道问题在于取消引用,而不是该行的其余部分。

如果您需要查看我的更多代码才能找到问题,请直接询问。我只是不想让你不必要地拖网数百行......

#include <vector>
#include "Entities.cpp"

struct Chunk {
    public:
        std::vector<BaseEntity>* environment; // this is what I'm trying to access

        Chunk() {
            environment = new std::vector<BaseEntity>(1); // this is where init

            environment->push_back(Grass()); // adding something to it works fine
        }

        ~Chunk() {
            delete(environment);
        }
};

class World {
    public:
        Chunk* loaded[3][3];

        World() {
            for (int x = 0; x < 3; x++)
                for (int y = 0; y < 3; y++) {
                    loaded[x][y] = new Chunk();
                }
        }

        ~World() {
            for (int x = 0; x < 3; x++)
                for (int y = 0; y < 3; y++) {
                    delete(loaded[x][y]);
                }
        }
};

这是访问它的代码(在另一个类和文件中)

void render(SDL_Renderer* gRenderer, Atlas* atlas, World* world, int SCREEN_WIDTH, int SCREEN_HEIGHT) {
        printf("1");
        for (int x = 0; x < 3; x++)
            for (int y = 0; y < 3; y++) {
                printf("2");
                std::vector<BaseEntity> env =
                        *(world->loaded[x][y]->environment); // here is where the error occurs
                printf("3");

                printf('0' + env.size() + "");
                printf("a");

                for (const auto& a : env) {
                    printf("b");
                    drawTexture(gRenderer, atlas, a.atlasID,
                            SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);
                }
                printf("4");
            }
        printf("5");

    }

这是调用它的代码:

int main(int argv, char** args) {
    SDL_Init( SDL_INIT_VIDEO );

    //The window we'll be rendering to
    SDL_Window* gWindow = SDL_CreateWindow(
         title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );

    if (gWindow == NULL) {
        printf("window error");
    }
    
    //Create renderer for window
    SDL_Renderer* gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED );
    if (gRenderer == NULL) {
        printf("renderer error");
    }

    bool quit = false; // quit flag

    //Event handler
    SDL_Event e;

    //nice little rendering class
    Renderer* renderer = new Renderer();

    //World
    World* world = new World();

    //Texture Atlas
    Atlas* atlas = new Atlas(SDL_GetWindowSurface( gWindow), gRenderer);


    //While application is running
        while( !quit )
        {
            //Handle events on queue
            while( SDL_PollEvent( &e ) != 0 )
            {

                switch(e.type) {
                    case SDL_QUIT: //User requests quit
                        quit = true;
                        break;
                }
                
            }

            //Clear screen
            //SDL_SetRenderDrawColor( gRenderer, 0, 0xFF, 0, 0xFF );
            SDL_RenderClear( gRenderer );

            renderer->render(gRenderer, atlas, world, SCREEN_WIDTH, SCREEN_HEIGHT);

            //Update the surface
            SDL_RenderPresent(gRenderer);
            //SDL_UpdateWindowSurface( gWindow );

        }

        delete (world, renderer, atlas);

        return 0;
}

【问题讨论】:

  • World *world 来自哪里?它是如何初始化的?
  • 我将其添加到问题中
  • “我只是不想让你不必要地浏览数百行代码......” 如果不需要数百行代码,那么很可能minimal reproducible example 是合适的。这也是一个很好的发展技能。继续删除代码,直到您的问题变得明显或您有一个非常小的程序来显示您的问题。
  • delete (world, renderer, atlas); 这可能不符合您的要求。 delete 不是这里的函数调用。 World 和 Chunk 违反了 3 的规则。

标签: c++ vector segmentation-fault


【解决方案1】:

我没有看到您的代码立即出现问题(除了复制向量显然效率低下),但我确实看到您的 printf 调试存在问题。

  1. 你应该使用fprintf(stderr, ...)来调试printfs,以避免stdio缓冲,或者调用fflush(NULL)
    3 未打印的事实并不一定意味着printf("3") 未到达。
  2. 您应该完全避免使用printf 调试,而是学习使用真正的调试器(GDB 或 LLDB)。
  3. 如果您使用 Address Sanitizer (-fsanitize=address) 运行程序;它可能会将您直接指向错误。

最后,在C++ 中写入时,请避免使用C 样式的数组,尤其是多级数组。请改用vectors。

【讨论】:

  • 我的控制台没有缓冲。我最初使用 printf 进行调试,但是当 printf 没有解决问题时,我很快就转到了 GDB。 -fsanitize=address 是编译器选项还是调试器选项?
  • fsanitize 似乎不适用于我的编译器 (MinGW)
  • @Skye "-fsanitize ..." -- 在这种情况下,您需要先创建一个stackoverflow.com/help/mcve,然后才能有人帮助您。在功能更强大的平台上进行开发将是另一个显而易见的选择。
【解决方案2】:

这分配了一个std::vector,其中一个元素为BaseEntity

environment = new std::vector<BaseEntity>(1); // this is where init

然后附加Grass 的另一个元素

environment->push_back(Grass()); // adding something to it works fine

但也许这是第一个问题,因为向量只包含BaseEntitys,请参阅What is object slicing?


这访问给定向量的第一个元素,这不是附加的Grass,而是来自new std::vector&lt;BaseEntity&gt;(1)的默认构造的BaseEntity对象

std::vector<BaseEntity> env = *(world->loaded[x][y]->environment); // here is where the error occurs

访问指针应该不是问题,因为它似乎已正确初始化。 但也许复制BaseEntity 是这里真正的问题。我会查看BaseEntity(可能还有Grass)的(复制)构造函数,看看是否有一些有问题的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-19
    • 2017-09-20
    • 1970-01-01
    相关资源
    最近更新 更多