我无法缩小此分段错误的原因
I can't narrow down the cause of this segmentation fault
我正在开发一个在 C++ 中使用 SFML 创建和显示毕达哥拉斯树的程序。我创建的 class 继承自具有纯虚函数 "draw" 的 SFML class 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 语句来测试,当我 运行 程序时它只打印一次,所以我假设它与我的指针有关而不是递归。感谢您的帮助!
你的问题是你有 leftPoint
和 rightPoint
形式的悬空指针。
您已将这些成员点从引用分配给堆栈分配的对象,这是一个问题,因为一旦这些对象超出范围,这些引用就会变成悬挂引用(它们不再指向内存中的有效位置)。此代码显示了您在哪里执行此操作
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
),它的生命周期与其所在范围的生命周期相关联(即只要对象存在,成员变量就存在).
这意味着当您将指针设置为指向 Left
和 Right
时,一旦方法执行完毕,它们就会变成悬挂指针(因为 Left
和 Right
超出范围)。这意味着您得到了 SIGSEGV,因为当您尝试使用它时该指针指向无效的内存位置! (在这种情况下,SIGSEGV 是最好的情况 btw :D)。
我建议选择 book on C++ 并了解指针、所有权和范围。您的代码充满了段错误,等待您使用引用和指针的方式发生 - 没关系,您的学习:)。
TL;DR 清理你的代码,不要用指针引用堆栈上的对象——这是一个等待发生的段错误
我正在开发一个在 C++ 中使用 SFML 创建和显示毕达哥拉斯树的程序。我创建的 class 继承自具有纯虚函数 "draw" 的 SFML class 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 语句来测试,当我 运行 程序时它只打印一次,所以我假设它与我的指针有关而不是递归。感谢您的帮助!
你的问题是你有 leftPoint
和 rightPoint
形式的悬空指针。
您已将这些成员点从引用分配给堆栈分配的对象,这是一个问题,因为一旦这些对象超出范围,这些引用就会变成悬挂引用(它们不再指向内存中的有效位置)。此代码显示了您在哪里执行此操作
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
),它的生命周期与其所在范围的生命周期相关联(即只要对象存在,成员变量就存在).
这意味着当您将指针设置为指向 Left
和 Right
时,一旦方法执行完毕,它们就会变成悬挂指针(因为 Left
和 Right
超出范围)。这意味着您得到了 SIGSEGV,因为当您尝试使用它时该指针指向无效的内存位置! (在这种情况下,SIGSEGV 是最好的情况 btw :D)。
我建议选择 book on C++ 并了解指针、所有权和范围。您的代码充满了段错误,等待您使用引用和指针的方式发生 - 没关系,您的学习:)。
TL;DR 清理你的代码,不要用指针引用堆栈上的对象——这是一个等待发生的段错误