1

I'm working on a program to create and display a Pythagoras Tree using SFML in C++. The class I've created inherits from the SFML class Drawable which has the pure virtual function "draw" and I believe the segFault is coming from my definition of this function.

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

After some debugging I found out that the segmentation Fault happens in the line leftTree.draw(target,state);in my draw function. I looked around online because I'm still a beginner and I know that this kind of error can be caused by pointers or recursion, I'm using both here so I dont know which is my problem. However, I added a print statement to test at the beginning of my function and it only prints once when I run the program so I'm assuming it has to do with my pointer rather than recursion. Any help is appreciated!

  • What IDE are you using? Set a breakpoint in your debugger to that line, and inspect the values of the tree to see if they are what you expect them to be. – JohnFilleau Feb 20 '20 at 23:34
  • Is `hasNext` ever `false`? If not, you'll recurse until you blow the stack. – 3Dave Feb 20 '20 at 23:34

1 Answers1

-1

Your problem is that you having dangling pointers in the form of leftPoint and rightPoint.

You have assigned these member points from references to stack allocated objects, this is a problem because once these objects go out of scope those references become dangling references (they no longer point to a valid location in memory). This code shows where you do it

    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

This has to do with the lifetime of stack objects. When an object is created on the stack (without the new operator or malloc), its lifetime is tied to the lifetime of the scope it lives in (i.e a member variable exists as long as the object exists).

This means that when you set your pointers to point at Left and Right they become dangling pointers as soon as the method finishes executing (as Left and Right go out of scope). This means you get your SIGSEGV as that pointer is pointing to an invalid memory location by the time you try and use it! (SIGSEGV is the best case scenario in this case btw :D).

I would suggest picking up a book on C++ and getting an understanding of pointers, ownership, and scope. Your code is full of segfaults waiting to happen in the way you are using references and pointers - which is ok, your learning :).

TL;DR clean up your code and don't reference objects on the stack with pointers - its a segfault waiting to happen

Object object
  • 1,939
  • 10
  • 19
  • thank you so much! just to clarify, the issue is that by the time I try to access the pointers in the draw function, the object they point to no longer exists because it went out of scope? – Missed Clips Feb 20 '20 at 23:58
  • Yep, your object gets deleted as soon as the function finishes and is long gone by the time `draw` is called – Object object Feb 20 '20 at 23:59
  • 1
    Also check out that book link, I would particularly recommend 'The C++ Programming Language' - Bjarne Stroustrup (creator of c++) if you have previous programming experience, its super helpful and presents a lot of useful concepts – Object object Feb 21 '20 at 00:04
  • This answer is misleading in several places: dangling is not the same `nullptr`, and stack objects have *nothing* to do with garbage collection. Objects that go out of scope are not deallocated, nor are they deleted (they are destructed). etc. etc. – Employed Russian Feb 21 '20 at 02:52
  • I agree, but i tried to keep the answer simple should i edit it and clarify that? – Object object Feb 21 '20 at 10:22