2016-06-25 3 views
3

小さなコード変更の背後にあるsegfaultの根本原因を突き止めようとしています。のは、問題なく実行されるコードのこの簡易版、始めましょう:どうやらテールノードが悪い親を取得するようC++のポインターとクラス階層がセグメンテーションパズルを起こしています

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

、ゲームのソース自体に、それは、セグメンテーションフォルトを行います。

child->parent = this;GameObject::addChildに移動し、this->parent = parent;TailNode::addToに移動すると動作します。

私はそれがポインターに関連していると推測しています。私はそれらを悪用しています。

あなたはhttps://github.com/spajus/sdl2-snake/tree/tail_working で完全に動作するコードベースを見つけ、それを壊すことにコミットすることができます:https://github.com/spajus/sdl2-snake/commit/4e92e9d6823420ce7554f2b6d7d19992c48d4acc

私はOS X 10.11.5上でそれをコンパイルし、実行している、

Apple LLVM version 7.3.0 (clang-703.0.31) 
Target: x86_64-apple-darwin15.5.0 
Thread model: posix 

コードが依存していますSDL2とその拡張のいくつか。

例のコンパイルコマンド:

$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 

私はあなたの代わりに裸なもののスマートポインタを使用することをお勧めします、とあなたは正しいかもしれないことを知っているが、ここで私はただ楽しんだし、見つけるために好奇心なぜそれがこのように壊れるのか。再現するのは難しいかもしれませんが(ビルドスクリプトはありますが)、目を覚ました経験豊富なC++開発者がすぐに問題を見つけるでしょう。

また、私は10年以上前に大学から何もやっていないので、コードレビューと改善の提案に感謝します。私のC++スキルはゼロに近いです。 (警告: - :

[/蛇/ tail_node.hpp含ま:13]> [:18 /蛇/ game_object.hppを含める]をorbitcowboyの先端に

答えて

2

おかげで、私はすぐに問題を発見したcppcheckを使用しました)クラス 'TailNode'は、親クラス 'GameObject'で定義された 'parent'という名前のメンバ変数を定義します。

GameObject* parentの再定義をTailNodeクラスから削除した後は、もはやセグメンテーションが解除されません。

問題を修正するコミット:https://github.com/spajus/sdl2-snake/commit/a1808e7d2426b5aedd9ab3a4dc2aa38aa0225a95

関連する問題