Удаление объекта из вектора портит объект в другом в C ++ - PullRequest
3 голосов
/ 04 августа 2011

В последние несколько дней я писал систему, облегчающую написание текстовых приключений (аналогично Colossal Cave или Zork). У меня возникла проблема с подсистемой Item.

Три рассматриваемых класса: Комната, Дверь и Предмет.

Когда я удаляю объект Item из вектора элемента комнаты, последний объект Door в векторе двери той же комнаты повреждается. Следует отметить, что все объекты Door и Item передаются по ссылке, что позволяет писать свои собственные подклассы Door и Item и при этом использовать их в системе. Что странно, так это то, что ЕДИНСТВЕННОЕ свойство поврежденного объекта двери - это атрибут «Местоположение», который сообщает игроку, где в комнате находится дверь. Все остальные атрибуты остаются нетронутыми, это говорит мне о том, что указатель на объект двери не был перемещен, но данные, на которые он указывает, были изменены.

Это вызывает ошибку в том, как игрок видит описания дверей. Для тестирования я не давал дверям специальных описаний, их слишком много, поэтому они используют мое внутреннее консервированное описание.

You are in a large parlour room.  It is obviously that of a very wealthy man.
Adorning the walls are many dusty heads of big game.
There is a door in the direction of West.
There is a door in the direction of East.
There is a door in the direction of North.
Hanging on the wall, you see a really bad ass looking sword.
Parlour] pickup sword
Picked up the Sword of the Gods
You pick up the sword.
In doing so, you feel very powerful.
There is a door in the direction of West.
There is a door in the direction of East.
There is a door in the direction of ?.
Parlour] 

Игрок все еще может перемещаться из комнаты в комнату, так что с остальными данными в дверном объекте все в порядке. Однако std :: string, в которой хранится свойство «Location», была изменена. Нигде в коде я не могу изменить этот атрибут.

Кто-нибудь может понять, почему это происходит? Есть ли у меня явно очевидная ошибка в моем коде или обработке объекта? Поскольку я не могу точно определить, в каком файле это происходит, необходимо опубликовать много кода.

Вы можете скачать zip-файл всего моего кода здесь: http://www.filedropper.com/advsys

Вот мой код, это, конечно, не все, так как у меня 467 строк в 9 файлах
Это называется, когда вы пытаетесь поднять меч.

void OnPickup() {
    std::cout << "You pick up the sword." << std::endl;
    std::cout << "In doing so, you feel very powerful." << std::endl;

    int itemNum = ParentRoom->HasItem(Name);
    if (itemNum != -1) {
        // Wait, the item ISN'T in the room?  Then how the hell did we get HERE?
        // Whatever, error out.
        std::cout << "For some strange reason, you were hallucinating about the " + Name + "." << std::endl;
    } else {
        PlayerRef->Inventory.push_back(new GodSword(ParentRoom, PlayerRef));
        ParentRoom->RemoveItem(itemNum);  // Corrupts a door
        //delete ParentRoom->Items[itemNum];  // SEGFAULT
    }
}

Двери и предметы распределяются следующим образом. Новому экземпляру двери передается текстовое местоположение, его положение в комнате и указатель на место назначения. Предметам передается ссылка на комнату, в которой они находятся, и ссылка на игрока.

house["parlour"].Doors.push_back(new Door("North", 'N', &house["bedroom"]));
house["parlour"].Items.push_back(new GodSword(&house["parlour"], &player));

Элементы удаляются из комнаты, как это. Распечатки дверей распечатаны для отладки.

void Room::RemoveItem(int item) {
    Items.erase(Items.begin() + item);

     for (int i = 0; i < Doors.size(); i++) {
         std::cout << Doors[i]->GetDescription() << std::endl;
     }
}

Декларация номеров ниже.

class Room {
    public:
        std::vector<Door *> Doors;
        std::vector<Item *> Items;

        std::string LongDescription;
        std::string ShortDescription;
        std::string Name;

        bool DescribeDoors;
        bool DescribeItems;
        bool BeenHere;

        Room();
        ~Room();

        int HasDoor(char dir);
        int HasItem(std::string name);
        void OutputDescription(bool forceLong=false);
        void RemoveItem(int item);
};

Я не могу думать ни о чем другом, что мне нужно добавить. Если вам нужно увидеть другой файл, или как объявлен другой класс, и т. Д ... Вы можете найти ссылку на zip выше.

Ответы [ 2 ]

3 голосов
/ 04 августа 2011

В этом коде, который вы разместили:

   int itemNum = ParentRoom->HasItem(Name);
    if (itemNum != -1) {
        // Wait, the item ISN'T in the room?  Then how the hell did we get HERE?
        // Whatever, error out.
        std::cout << "For some strange reason, you were hallucinating about the " + Name + "." << std::endl;
    } else {
        PlayerRef->Inventory.push_back(new GodSword(ParentRoom, PlayerRef));
        ParentRoom->RemoveItem(itemNum);  // Corrupts a door
        //delete ParentRoom->Items[itemNum];  // SEGFAULT
    }

itemNum будет равен -1, когда вы попытаетесь удалить его, что, вероятно, приведет к повреждению сегмента / памяти, которое вы заметили. Неужели смысл теста не такой, каким он должен быть?

0 голосов
/ 04 августа 2011

Дьютелл обнаружил ошибку, вызывающую повреждение памяти.Однако истинная ошибка в коде лежит в этой строке:

int itemNum = ParentRoom->HasItem(Name);

, как и должно быть:

int itemNum = ParentRoom->HasItem(PickupName);

В противном случае совпадение не может быть найдено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...