开发者

Removing object from vector corrupts object in another in C++

For the past few days, I have been writing a system to ease the writing of text-based adventures (similar to Colossal Cave or Zork). I've been running into an issue with the Item subsystem.

The three classes concerned are Room, Door, and Item.

When I remove an Item object from a Room's item vector, the last Door object in the same room's Door vector is corrupted. It should be noted that all Door and Item objects are passed by reference, this allows one to write their own Door and Item subclasses and still use them with the system. What's strange, is that the ONLY property of the door object to be corrupted is the "Location" attribute, which tells the player where in the room the door is. All other attributes are left untouched, this tells me that the pointer to the door object has not been moved, but the data it points to has been altered.

What this causes is an error in how the player sees door descriptions. For testing, I didn't give the doors special descriptions, there are too many of them, so they use my internal, canned description.

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] 

The player can still move from room to room, so the rest of the data in the door object is seemingly okay. However, the std::string that stores the "Location" property has been changed. Nowhere in the code do I change that attribute.

Can anyone see why this is happening? Do I have a blatantly obvious error in my code or object handling? Because I cannot pinpoint in which file this is occurring, there is a lot of code to be posted.

You can download a zip file of all of my code here: http://www.filedropper.com/advsys

Here's my code, this certainly isn't all of it, as I have 467 lines over 9 files

This is called when you attempt to pick up the sword.

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
    }
}

Doo开发者_StackOverflowrs and Items are allocated like this. A new Door instance is passed the text-location, it's position within the room, and a pointer to the destination. Items are passed a reference to the room they are in, and a reference to the player.

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

Items are deleted from the room like this. The door listings are printed for debugging.

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;
     }
}

The Room declaration is below.

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);
};

I can't think of anything else I need to add. If you need to see another file, or how a different class is declared, etc... There is a link to a zip above.


In this code that you posted:

   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 will be -1 when you attempt to remove it, which will probably lead to the segfault/memory corruption you noticed. Is the sense of the test inverted from what it should be?


Dewtell spotted the bug causing the memory corruption. However, the true error in the code lies at this line:

int itemNum = ParentRoom->HasItem(Name);

as it should be:

int itemNum = ParentRoom->HasItem(PickupName);

Otherwise the match can never be found.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜