ここ数日間、私はテキストベースの冒険(Colossal CaveやZorkに似ています)の書き方を簡単にするシステムを書いています。私はItemサブシステムの問題にぶち当たっています。ベクトルからオブジェクトを削除すると、別のオブジェクトがC++で破損する
3つのクラスはルーム、ドア、アイテムです。
ルームのアイテムベクトルからアイテムオブジェクトを削除すると、同じルームのドアベクトルの最後のドアオブジェクトが壊れています。すべての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が変更されています。コードのどこにもその属性を変更する必要はありません。
これはなぜ起こっているのですか?私はコードやオブジェクトの取り扱いに大変明白なエラーがありますか?このファイルがどのファイルで発生しているのかを特定できないため、投稿するコードがたくさんあります。
あなたはここに私のコードのすべてのzipファイルをダウンロードすることができます:http://www.filedropper.com/advsys
はここに私のコードですが、これは確かに私は9つのファイル以上467行
を持っているとして、これはときに呼び出され、それがすべてではありません剣を拾おうとする。
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
}
}
ドアとアイテムはこのように割り当てられます。 新しいDoorインスタンスがtext-location、部屋内の位置、および宛先へのポインタを渡されます。アイテムには、自分がいる部屋への参照と、プレイヤーへの参照が渡されます。
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);
};
私は追加する必要があるとは思いません。別のファイルを見る必要がある場合や、別のクラスがどのように宣言されているかなど...上記のジッパーへのリンクがあります。
私は最近、 'std :: map'に同様の問題があり、segfaultが発生しました。この問題は 'std :: map <> :: iterator'ループの中で' erase() 'と' gmtime_r() 'を呼び出すことによって引き起こされました、' gmtime_r() 'が何も指されていないにもかかわらず、地図。 'erase()' *や* 'gmtime_r()'を削除することで問題は解決しました。私は短い期限があったので、ここでは投稿しなかったし、 'erase()'を呼び出すのではなく、エントリにフラグを設定することで問題を解決(延期)した。フラグを付けられたエントリを探して 'erase()'を呼び出す最初のイテレータループの後にもう1つのイテレータループを追加しました。 – wallyk
これは無関係かもしれませんが、私はここで少し失われています。 'Room :: HasItem'は本質的に' IndexOf'操作ですが、サンプルコードの存在条件は 'if(itemNum!= -1)'と表示されます。たぶん私の目はぼやけていますが、これは正しいです。アイテムが見つからない場合にのみ 'RemoveItem'ブロックをたどるように見えます。その場合、' Items.erase(Items.begin( )+(-1)); ' –
ポインタを使用して手動でヒープに割り当てる理由は何ですか?コンテナにメモリを管理させ、より効率的な挿入と削除のために 'std :: list'を使いたいかもしれません。 P.S.私はQuintinがあなたのバグを釘付けにしたと信じています。 – AJG85