简体   繁体   English

导致段错误的C ++指针和类层次结构

[英]C++ pointers and class hierarchy causing a segfault puzzler

I am trying to figure out a root cause of a segfault behind a small code change. 我试图找出一个小代码更改背后的段错误的根本原因。 Let's begin with this simplified version of code, which runs without issues: 让我们从这个简化版本的代码开始,它运行没有问题:

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

Now, in the game source itself, it does segfault, as apparently tail node gets a bad parent. 现在,在游戏源本身,它确实是段错误,因为显然尾节点得到了一个糟糕的父节点。

When I move child->parent = this; 当我移动child->parent = this; away from GameObject::addChild and use this->parent = parent; 远离GameObject::addChild并使用this->parent = parent; at TailNode::addTo , it works. TailNode::addTo ,它的工作原理。

I am guessing it is related to pointers and the way I am misusing them. 我猜它与指针和我滥用它们的方式有关。

You can find the full working codebase at https://github.com/spajus/sdl2-snake/tree/tail_working And the commit that breaks it: https://github.com/spajus/sdl2-snake/commit/4e92e9d6823420ce7554f2b6d7d19992c48d4acc 您可以在https://github.com/spajus/sdl2-snake/tree/tail_working找到完整的工作代码库以及打破它的提交: https//github.com/spajus/sdl2-snake/commit/4e92e9d6823420ce7554f2b6d7d19992c48d4acc

I'm compiling and running it on OS X 10.11.5, 我正在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

Code depends on SDL2 and few of it's extensions. 代码取决于SDL2及其中的一些扩展。

Example compilation command: 示例编译命令:

$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

I know that you will recommend to use smart pointers instead of naked ones, and you may be right, but here I'm just having fun and am curious to find out why it breaks this way. 我知道你会建议使用智能指针而不是裸指针,你可能是对的,但在这里,我只是很开心,很想知道它为什么会这样打破。 It may be difficult to reproduce (there are build scripts though), but perhaps an experienced C++ developer with a good eye will spot the problem right away. 可能很难重现(虽然有构建脚本),但是有经验的C ++开发人员可能会立即发现问题。

Also, I appreciate a code review and improvement suggestions, my C++ skills are close to zero, as I haven't done anything with it since university over a decade ago. 此外,我感谢代码审查和改进建议,我的C ++技能接近于零,因为自从大学十多年前我没有做过任何事情。

Thanks to orbitcowboy's tip, I used cppcheck which found the issue right away: 感谢orbitcowboy的提示,我使用cppcheck找到了问题:

[include/snake/tail_node.hpp:13] -> [include/snake/game_object.hpp:18]: (warning) The class 'TailNode' defines member variable with name 'parent' also defined in its parent class 'GameObject'. [include / snake / tail_node.hpp:13] - > [include / snake / game_object.hpp:18] :(警告)类'TailNode'定义名称为'parent'的成员变量,也在其父类'GameObject'中定义。

After removing the redefinition of GameObject* parent from TailNode class, it no longer segfaults. TailNode类中删除TailNode GameObject* parent的重新定义后,它不再是段错误。

Commit that fixes the issue: https://github.com/spajus/sdl2-snake/commit/a1808e7d2426b5aedd9ab3a4dc2aa38aa0225a95 提交修复问题: https//github.com/spajus/sdl2-snake/commit/a1808e7d2426b5aedd9ab3a4dc2aa38aa0225a95

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM