【问题标题】:I can't narrow down the cause of this segmentation fault我无法缩小此分段错误的原因
【发布时间】:2020-02-20 23:30:21
【问题描述】:

我正在开发一个使用 C++ 中的 SFML 创建和显示毕达哥拉斯树的程序。我创建的类继承自具有纯虚函数“draw”的 SFML 类 Drawable,我相信 segFault 来自我对这个函数的定义。

#include <cmath>
#include <SFML/Graphics.hpp>
#include <vector>

class PTree: public sf::Drawable{
public:
    PTree(float length);
    PTree(sf::RectangleShape shape);
    ~PTree(){};
    void pTree(int depth);
    virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
private:
    sf::RectangleShape square;
    PTree* leftPoint;
    PTree* rightPoint;
    bool hasNext;
};

PTree::PTree(float length){
    sf::Vector2f size(length,length);
    sf::RectangleShape shape(size);
    square = shape;
    square.setFillColor(sf::Color::Red);
    square.setPosition(5.5*length,6.5*length);
    hasNext = true;
}

PTree::PTree(sf::RectangleShape shape){
    square = shape;
    square.setFillColor(sf::Color::Red);
    hasNext = true;
}

void PTree::pTree(int depth){
    if(depth == 0){
        this->leftPoint = NULL;
        this->rightPoint = NULL;
        this->hasNext = false;
        return;
    }
    sf::Vector2f oldSize = this->square.getSize();
    float oldL = oldSize.x;
    float newL = sqrt(pow(oldL,2)/2);
    sf::Vector2f newSize(newL,newL);
    sf::Vector2f point1 = this->square.getPoint(0);
    sf::Vector2f point2 = this->square.getPoint(1);
    sf::RectangleShape left(newSize);
    sf::RectangleShape right(newSize);
    left.setOrigin(0,0-newL);
    right.setOrigin(newL,0-newL);
    left.setPosition(point1);
    right.setPosition(point2);
    left.rotate(45);
    right.rotate(-45);
    PTree Left(left);
    PTree Right(right);
    leftPoint = &Left;
    rightPoint = &Right;
    Left.pTree(depth-1);
    Right.pTree(depth-1);

}

void PTree::draw(sf::RenderTarget& target, sf::RenderStates states) const{
    target.draw(this->square);
    if(!hasNext){
        return;
    }
    PTree& leftTree = *leftPoint;
    PTree& rightTree = *rightPoint;
    leftTree.draw(target,states);   //this is where the error occurs
    rightTree.draw(target,states);
}

int main(int argc, char* argv[]){
  float length = atof(argv[1]);
  int depth = atoi(argv[2]);
  PTree tree(length);
  tree.pTree(depth);
  float windowH = 8 * length;
  float windowW = 12 * length;
  sf::RenderWindow window(sf::VideoMode(windowW,windowH), "Pythagoras Tree");
   while(window.isOpen()){
        sf::Event event;
        while(window.pollEvent(event)){
            if(event.type == sf::Event::Closed)
              window.close();
        }
        window.clear();
        tree.draw(window,sf::RenderStates::Default);
        window.display();
   }
}

经过一些调试,我发现分段错误发生在我的绘图函数中的leftTree.draw(target,state);行中。我在网上看了一圈,因为我还是一个初学者,我知道这种错误可能是由指针或递归引起的,我在这里都使用了,所以我不知道哪个是我的问题。但是,我在函数的开头添加了一个 print 语句来测试,它只在我运行程序时打印一次,所以我假设它与我的指针而不是递归有关。任何帮助表示赞赏!

【问题讨论】:

  • 您使用的是什么 IDE?在调试器中为该行设置断点,并检查树的值以查看它们是否符合您的预期。
  • hasNext 曾经是false 吗?如果没有,你会递归直到你把堆栈炸掉。

标签: c++ segmentation-fault sfml


【解决方案1】:

你的问题是你有leftPointrightPoint形式的悬空指针。

您已将这些成员点从引用分配给堆栈分配的对象,这是一个问题,因为一旦这些对象超出范围,这些引用就会成为悬空引用(它们不再指向内存中的有效位置)。这段代码显示了你在哪里做的

    PTree Left(left); // <-- Here and
    PTree Right(right); // <-- Here you create left and right on the stack
    leftPoint = &Left; // <-- Here
    rightPoint = &Right; // <-- And here you assign the pointers as references to the stack objects

这与堆栈对象的生命周期有关。当在堆栈上创建对象时(没有new 运算符或malloc),它的生命周期与它所在的范围的生命周期相关联(即,只要对象存在,成员变量就存在)。

这意味着当您将指针设置为指向 LeftRight 时,只要方法完成执行,它们就会变成悬空指针(因为 LeftRight 超出范围)。这意味着您获得了 SIGSEGV,因为当您尝试使用它时,该指针指向了一个无效的内存位置! (在这种情况下,SIGSEGV 是最好的情况,顺便说一句:D)。

我建议选择book on C++ 并了解指针、所有权和范围。您的代码充满了段错误,等待您使用引用和指针的方式发生 - 没关系,您的学习:)。

TL;DR 清理您的代码并且不要使用指针引用堆栈上的对象 - 这是等待发生的段错误

【讨论】:

  • 非常感谢!澄清一下,问题是当我尝试访问绘图函数中的指针时,它们指向的对象不再存在,因为它超出了范围?
  • 是的,一旦函数完成,您的对象就会被删除,并且在调用 draw 时早已不复存在
  • 还可以查看该书的链接,如果您有以前的编程经验,我特别推荐“C++ 编程语言”- Bjarne Stroustrup(c++ 的创建者),它非常有用并提供了许多有用的概念
  • 这个答案在几个地方有误导性:悬空与nullptr 不同,堆栈对象与垃圾收集没有任何关系。超出范围的对象不会被释放,也不会被删除(它们被破坏)。等等等等。
  • 我同意,但我试图让答案保持简单,我应该编辑它并澄清它吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-12
  • 1970-01-01
  • 2014-08-29
  • 1970-01-01
相关资源
最近更新 更多