Ich versuche, eine Grundursache eines segfault hinter einer kleinen Codeänderung herauszufinden. Lassen Sie sich mit dieser vereinfachten Version des Codes beginnen, die ohne Probleme läuft:C++ - Zeiger und Klassenhierarchie, die einen segfault puzzler verursachen
#include <iostream>
#include <string>
#include <vector>
class GameObject {
public:
virtual void update();
void addChild(GameObject* child);
GameObject* parent;
std::vector<GameObject*> children;
int x;
int y;
};
class Player : public GameObject {
public:
void growTail();
void update();
};
class TailNode : public GameObject {
public:
void addTo(GameObject* parent);
void update();
// UPDATE AFTER ANSWER IS CLEAR: this was in original codebase and it was causing the segfault
GameObject* parent;
};
void GameObject::addChild(GameObject* child) {
this->children.push_back(child);
child->parent = this; // <- can't do this in full codebase, causes segfault later
}
void GameObject::update() {
for (GameObject* child : children) {
child->update();
}
}
void Player::update() {
GameObject::update();
std::cout << "Player at: ["
<< std::to_string(x)
<< std::to_string(y)
<< "]"
<< std::endl;
}
void Player::growTail() {
TailNode* tail = new TailNode();
tail->addTo(this);
}
void TailNode::update() {
GameObject::update();
std::cout << "Tail parent at: ["
<< std::to_string(parent->x) // <- if parent is set inside GameObject::addChild, this segfaults in full codebase
<< std::to_string(parent->y)
<< "]"
<< std::endl;
}
void TailNode::addTo(GameObject* parent) {
parent->addChild(this);
// this->parent = parent; <-- have to do this to avoid segfault in full codebase
}
int main() {
Player* player = new Player();
player->x = 10;
player->y = 11;
player->growTail();
player->update();
}
nun im Spiel Quelle selbst, es tut segfault, wie scheinbar Endknoten ein schlecht Eltern bekommt.
Wenn ich child->parent = this;
weg von GameObject::addChild
verschiebe und this->parent = parent;
bei TailNode::addTo
verwende, funktioniert es.
Ich vermute, es ist mit Zeigern und die Art, wie ich sie missbrauche verwandt.
Sie können die volle Arbeits Code-Basis bei https://github.com/spajus/sdl2-snake/tree/tail_working finden Und das sagen zu, dass es bricht: https://github.com/spajus/sdl2-snake/commit/4e92e9d6823420ce7554f2b6d7d19992c48d4acc
ich kompilieren und es auf OS X 10.11.5 läuft,
Apple LLVM version 7.3.0 (clang-703.0.31)
Target: x86_64-apple-darwin15.5.0
Thread model: posix
-Code hängt davon ab, SDL2 und einige seiner Erweiterungen. Kompilation Befehl
Beispiel:
$XCODE/XcodeDefault.xctoolchain/usr/bin/c++ \
-I/Library/Frameworks/SDL2.framework/Headers \
-I/Library/Frameworks/SDL2_image.framework/Headers \
-I/Library/Frameworks/SDL2_mixer.framework/Headers \
-I/Library/Frameworks/SDL2_ttf.framework/Headers \
-I$HOME/Dev/sdl2-snake/include \
-Wall -Wextra -pedantic -std=c++11 \
-Wall -Wextra -pedantic -std=c++11 \
-g -g -o CMakeFiles/Snake.dir/src/main.cpp.o \
-c $HOME/Dev/sdl2-snake/src/main.cpp
Ich weiß, dass Sie intelligente Zeiger statt nackt diejenigen zu verwenden, werden empfohlen, und Sie können richtig sein, aber hier bin ich einfach nur Spaß und bin gespannt, um herauszufinden, Warum bricht es so? Es mag schwierig zu reproduzieren sein (es gibt Build-Skripte), aber vielleicht wird ein erfahrener C++ - Entwickler mit einem guten Auge das Problem sofort erkennen.
Auch ich schätze eine Code-Review und Verbesserungsvorschläge, meine C++ - Fähigkeiten sind nahe bei Null, da ich seit der Universität vor über einem Jahrzehnt nichts damit getan habe.