Vectors, "virtual", Segmentation Fault on function call
I'm getting a Segmentation Fault when trying to call a function that is within a object that is part of a vector of "Shape" Pointers
My problem is in this function::
Point findIntersection(Point p, Point vecDir, int *status)
{
Point noPt;
for (int i = 0; i < shapes.size(); i++)
{
Point temp;
cout << "Shapes size" << shapes.size() << endl;
**SEGMENTATIONFAULT HERE >>>>>** bool intersect = shapes[0]->checkIntersect(p, vecDir, &temp);
if (intersect)
{
*status = 1; // Code 1 for intersecting the actual shape
return temp;
}
}
return noPt;
}
Initially, I am only adding one shape:
void createScene()
{
image = QImage(width, height, 32); // 32 Bit
Sphere s(Point(0.0,0.0,-50.0), 40.0);
shapes.push_back(&s);
cout << shapes.size() <<endl;
}
So I have a vector of "shapes" which is global. vector shapes;
I have a class shape
#include "Point.h"
#ifndef SHAPE_H
#define SHAPE_H
using namespace std;
class Shape
{
public:
Shape() {}
~Shape(){}
virtual bool checkIntersect(Point p, Point d, Point *temp) {}; // If intersects, return true else false.
virtual void printstuff() {};
};
#endif
and also a Sphere class
#include "shape.h"
#include <math.h>
#include <algorithm>
using std::cout;
using std:: endl;
using std::min;
class Sphere : public Shape
{
public:
Point centerPt;
double radius;
Sphere(Point center, double rad)
{
centerPt = center;
radius = rad;
}
bool checkIntersect(Point p, Point vecDir, Point *temp)
{
cout << "Hi" << endl;
/*
Point _D = p - centerPt;
double a = Point :: dot(vecDir, vecDir);
double b = 2 * ( Point :: dot(vecDir, _D) );
double c = (Point :: dot(_D,_D)) - (radius * radius);
// Quadratic Equation
double tempNum = b * b - 4 * a * c;
if (tempNum < 0)
{
return false;
} else
{
double t1 = ( -b + sqrt(tempNum) ) / (2 * a);
double t2 = ( -b - sqrt(tempNum) ) / (2 * a);
double t;
if (t1 < 0 && t2 > 0) { t = t2; }
else if (t2 < 0 && t1 > 0) { t = t1; }
else if ( t1 < 0 && t2 < 0 ) { return false; }
else
{
t = min(t1, t2);
}
Point p1 = p + (vecDir * t);
if (p1.z > 0) // Above our camera
{
return false;
} else
{
temp = 开发者_开发知识库&p1;
return true;
}
}
*/
return false;
}
};
The problem is here:
Sphere s(Point(0.0,0.0,-50.0), 40.0);
shapes.push_back(&s);
at this point, you've created the Sphere s
locally on the stack, and you've pushed its address into your vector. When you leave scope, local objects are freed, and so the address you've stored in your vector now points to memory you no longer own and its contents is undefined.
Instead, do
Sphere *s = new Sphere(Point(0.0,0.0,-50.0), 40.0);
shapes.push_back(s);
to allocate the Sphere from the heap so that it persists. Make sure to delete
it when you are done with it.
You put an address of a local variable in your vector shapes.After exit from your function createScene() this address becomes invalid.
void createScene()
{
image = QImage(width, height, 32); // 32 Bit
Sphere s(Point(0.0,0.0,-50.0), 40.0);
shapes.push_back(&s);
cout << shapes.size() <<endl;
}
Quoting:
Sphere s(Point(0.0,0.0,-50.0), 40.0);
shapes.push_back(&s);
You're putting the address of a local variable in a global collection. Two lines later, s
goes out of scope and &s
becomes invalid.
The problem is your "createScene" function:
void createScene() { image = QImage(width, height, 32); // 32 Bit Sphere s(Point(0.0,0.0,-50.0), 40.0); shapes.push_back(&s); cout << shapes.size() <<endl; }
The object s
has been allocated within the stack frame of the "createScene" function. It is a local variable, and it will be destructed and invalidated as soon as the "createScene" function ends. Therefore, you have put a pointer to a non-existent object into your shapes vector. What you should do, instead, is allocate a Shape object on the heap (perhaps storing it in a boost::shared_ptr?) and put that in the vector.
Apparently you do not have a vector of shapes, but a vector of pointers to shapes. In createScene
you add a pointer to a local variable to that vector. When the method finishes, that local is destroyed. When you try to do a call on the object later, you try to make a call on an object that does not exists.
You can solve that problem by using boost::shared_ptr as the argument type of you vector.
// definition of you vector
std::vector< boost::shared_ptr< Shape > > shapes;
void createScene()
{
image = QImage(width, height, 32); // 32 Bit
boost::shared_ptr< Shape >( new Sphere s(Point(0.0,0.0,-50.0), 40.0) );
shapes.push_back(s);
cout << shapes.size() <<endl;
}
UPDATE: You can also use Boost.PointerContainer instead of a smart pointer, if the container is supposed to actually own the objects.
Your example will not compile like this. This implementation must return a value:
virtual bool checkIntersect(Point p, Point d, Point *temp) {};
If your global vector of shapes contains a NULL pointer, shapes.size()
will be non-zero yet shapes[0]->checkIntersect
will fail.
In general, use a debugger (gdb, Visual Studio) and step through your code. Check every variable and you will surely find the problem.
void createScene()
{
image = QImage(width, height, 32); // 32 Bit
Sphere s(Point(0.0,0.0,-50.0), 40.0);
shapes.push_back(&s);
cout << shapes.size() <<endl;
}
your Sphere s(Point(0.0,0.0,-50.0), 40.0);
here is a local variable that gets destroyed when CreateScene
ends. You push &s
, a pointer to s into your shapes vector, so once CreateScene
finishes (i.e. after the last cout statement above) shapes[0]
points to some destroyed object.
Change to:
void createScene()
{
image = QImage(width, height, 32); // 32 Bit
Sphere* s_p = new Sphere(Point(0.0,0.0,-50.0), 40.0);
shapes.push_back(s_p);
cout << shapes.size() <<endl;
}
And don't forget to delete all items in shapes
before you remove them from shapes
.
精彩评论