【问题标题】:Strange segmentation faults - pushing back an object pointed by pointer to a vector causes crash奇怪的分段错误 - 将指针指向的对象推回向量会导致崩溃
【发布时间】:2012-10-28 14:35:54
【问题描述】:

我正在尝试使用 SDL 编写游戏,但我遇到了很多奇怪的段错误。

我创建了 Monster 和 Player 类,它们从 Creature 类中获取公共变量。类 Creature 从类 Object 中获取变量。就这样:

class Object {
public:
    Area* area_pointer; // Pointer to an Area in which object is present.
    Sprite sprite; // Class that has SDL_Surface* and some other things.
    Animation animation; // nothing usefull
    int ID;
    short int position_x; // nothing usefull
    short int position_y; // nothing usefull
    short int effect_x; // nothing usefull
    short int effect_y; // nothing usefull
    .... //Some functions that are not important right now.
};

类精灵:

class Sprite {
public:
    SDL_Surface* image;
    short int x;
    short int y;
    short int w;
    short int h;
    Sprite ()
    {
        image = NULL;
        x = 0;
        y = 0;
        w = 0;
        h = 0;
    }   
};

类生物、玩家、怪物:

class Creature : public Object {
        public:
            char move_direction;
            char speed; 
            ..// Some not important functions.
};
class Player : public Creature {
        public:
            char select_type;
            int select_ID;
            std::vector <Item> equip;
            std::vector <Item> inventory;
            std::vector <Effect> effects;
            Player (Area* c_area_pointer, int data [])
            {
                area_pointer = c_area_pointer;
                sprite.image = SurfaceLoad ("Images/Players/" + IntToString (data [0]) + ".png");
                sprite.x = 0;
                sprite.y = 0;
                sprite.w = 0;
                sprite.h = 0;
                ID = data [0];
                position_x = data [1];
                position_y = data [2];
                effect_x = 0;
                effect_y = 0;
            }
            ~Player ()
            {
                SDL_FreeSurface (sprite.image);
                .....
            }
};
class Monster : public Creature {
        public:
            char type;
            std::vector <Item> loot;
            std::vector <Effect> effects;
            Monster (Area* c_area_pointer, int data [])
            {
                area_pointer = c_area_pointer;
                sprite.image = SurfaceLoad ("Images/Monsters/" + IntToString (data [3]) + ".png");
                sprite.x = 0;
                sprite.y = 0;
                sprite.w = 0;
                sprite.h = 0;
                ID = data [0];
                position_x = data [1];
                position_y = data [2];
                effect_x = 0;
                effect_y = 0;
                type = data [3];
            }
            ~Monster ()
            {
                SDL_FreeSurface (sprite.image);
                .....
            }
};

SurfaceLoad 函数:

SDL_Surface* SurfaceLoad (std::string file_name)
{
SDL_Surface* surface_1 = NULL;
SDL_Surface* surface_2 = NULL;
surface_1 = IMG_Load (file_name.c_str ());
surface_2 = SDL_DisplayFormat (surface_1);
if (surface_1 != surface_2) SDL_FreeSurface (surface_1); // This line may be strange to some of you, but it is related to other error i had in past.
SDL_SetColorKey (surface_2, SDL_SRCCOLORKEY, 0xFFFFFF);
return surface_2;
}

我尝试从 txt 文件中加载数据并根据它制作对象。我使用我自己的 Load 函数。它创建一个指向类对象的指针,例如:

        Player* player;
        std::string players_name = save_name + "Areas/" + IntToString (ID) + "/players.txt"; //Path to the file cointaining players data.
        std::ifstream players_file;
        players_file.open (players_name.c_str ());
        Monster* monster;
        std::string monsters_name = save_name + "Areas/" + IntToString (ID) + "/monsters.txt"; //Path to the file cointaining monsters data.
        std::ifstream monsters_file;
        monsters_file.open (monsters_name.c_str ());

然后它从文本文件中加载数据并将其放入名为 file_data 的 int 数组中,并基于它创建新的类对象。

        while (!players_file.eof ())
        {
            getline (players_file, file_text);
            while (file_text [data_position_2 + 1] != ';')
            {
                data_position_2 = file_text.find (",", data_position);
                data.assign (file_text, data_position, data_position_2 - data_position);
                file_data [data_index] = atoi (data.c_str ());
                data_position = data_position_2 + 1;
                data_index++;
            }
            player = new Player (this, file_data);
            this->area_map.players.push_back (*player); //Vector players inside object area_map which contain also monsters vector. "this" is a pointer to object that contain Load function and area_map object.
            delete player;
            data_index = 0;
            data_position = 0;
            data_position_2 = 0;
        }

这部分代码可以工作,但是对 monsters_file 和 monsters vector 做同样的事情会导致很多奇怪的错误。我得到的第一个错误是在将数据指针推入向量后删除指针时出现段错误。我检查了一下,发现程序在调用 SDL_FreeSurface() 时在解构器中崩溃(segfault)。所以我检查了我的构造函数是否正确加载了表面。我发现构造一个对象一切正常,但是在调用 SurfaceLoad() 时它突然开始崩溃(segfault)。也检查了这个函数,一切都很好:指向表面的指针是好的,它返回的指针是好的,但由于某种原因它崩溃了:

sprite.image = SurfaceLoad (...);

在它停止崩溃后的一段时间,没有任何理由(我只是添加了那行

if (surface_1 != surface_2) SDL_FreeSurface (surface_1);

,因为我注意到 SDL_DisplayFormat () 有时会返回与指向未格式化表面的指针相同的指针。)并在我 push_back 指向向量的指针指向的对象时开始崩溃(段错误):

this->area_map.monsters.push_back (*monster);

Monster 和 Player 类在创建游戏的这个阶段几乎相同,所以我不知道为什么它可以毫无问题地创建玩家,并且创建怪物有这么多问题。有谁知道如何解决这个问题?

【问题讨论】:

    标签: c++ pointers vector segmentation-fault sdl


    【解决方案1】:

    大量代码看起来有点杂乱无章。例如,为什么 Player 析构函数会释放 Sprite 中声明的图像?这不应该是 Sprite 析构函数的工作吗?为什么一切都是公开的?但无论如何,从你描述的症状来看,这听起来像是一个不遵守三规则的经典案例。

    当您编写在内部分配内存或其他资源的类(如 Sprite 中的图像指针)时,您必须编写正确处理分配的内存或资源的复制构造函数和赋值运算符。如果你不这样做,你会得到这样的错误。

    请参阅here 了解有关三法则的一些基本信息。如果您不了解这些内容,那么您将一直在编写错误的 C++ 代码。关于管理资源的部分与您最相关,但请通读。

    【讨论】:

    • 非常感谢您的回答。我为 Monster 类创建了复制构造函数,它现在可以工作了,所以我现在要为每个类创建这些构造函数。似乎我必须学习比我想象的更多,但无论如何再次感谢并抱歉发布这么多代码。我只想发布您需要的所有内容。
    • @Mittorn 代码太多总比太少好。您不需要为每个类编写这些构造函数,只需那些显式管理资源的构造函数即可。
    • 对不起,我写错了。在写“我将为每个类创建这些构造函数”时,我在考虑以类似于 Players 的方式加载的每个类。
    猜你喜欢
    • 1970-01-01
    • 2018-10-19
    • 1970-01-01
    • 1970-01-01
    • 2018-01-23
    • 1970-01-01
    • 2015-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多