i try to sort a vector which element-type is a class like following:
void sort_test() {
class A{
public:
A(float x, float y, float z):score_(x),rerank_score_(y),ranking_score_(z) {};
float score_;
float rerank_score_;
float ranking_score_;
};
using A_ptr = std::shared_ptr<A>;
auto CompareA_ptr = [](A_ptr x, A_ptr y) {
if (x == nullptr && y != nullptr) {
return false;
} else if (x == nullptr && y == nullptr) {
return false;
} else if (x != nullptr && y == nullptr) {
return true;
} else {
if (x->rerank_score_ > y->rerank_score_) {
return true;
} else if (x->rerank_score_ < y->rerank_score_) {
return false;
} else {
if (x->score_ > y->score_) {
return true;
} else if (x->score_ < y->score_) {
return false;
} else {
return x->ranking_score_ >= y->ranking_score_;
}
}
}
};
std::vector<A_ptr> X;
for (int i = 0; i < 7; ++i) {
X.push_back(std::make_shared<A>(A(0.1, 0.1, 0.1)));
}
std::sort(X.begin(), X.end(), CompareA_ptr);
}
int main(){
sort_test();
return 0;
}
I run the code in Xcode and get the Xcode error "Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)"in memory.cpp:
I found that the code runs correctly when the vector size is less than 7, and an error is reported when the vector size is greater than 7. It bothers me a lot.
Appreciate for any reply.
Testing your code in Visual Studio revelas that CompareA_ptr doesn't define a strict weak ordering as required for a comparator. This causes undefined behaviour.
The culprit seems to be
return x->ranking_score_ >= y->ranking_score_;
where >= should be changed to >
return x->ranking_score_ > y->ranking_score_;
Related
I'm creating a function that creates a map from an image with a maze in it.
It takes the image, goes to every pixel and decides if it has to create a node there. One rule is, that when it finds a white pixel at one of the borders it will either be the start or the end node. To tell my pathfinding function where to start, I push the node into a vector(like all other nodes, too) and save the address of that node in a (double)pointer. My problem is, at the end of the loop, the variables in this node change their values(a bool variable might get the value 133) I actually never modify most of the members in this loop. I really have no idea why this is the case...
For examle:
After assigning the node to the pointer:
Completed: false
DistanceTo: 4294967295
PreviousNode: 0x0
XPos: 3
YPos: 0
m_vConnections: <0 Elements>
After function finished:
Completed: 8
DistanceTo: 32674
PreviousNode: SomeAddress
XPos: 3
YPos: 0
m_vConnections: <0 Elements>
The node at SomeAddress actually has completely screwed values, too, but I suspect that the address just changed and it now interprets the data found there as a node.
Sometimes m_vConnections becomes "inaccesseble" which results in sigsegvs when I try to connect something to it.
My function:
bool CreateGraph(const sf::Image &mMaze, std::vector<dijkstra::CNode> *vGraph, dijkstra::CNode **mStart, dijkstra::CNode **mEnd, SMazeCol mColors)
{
*mStart = 0;
unsigned short nExits = 0;
//Get Maze Colours
sf::Color mWallColor = mColors.Wall;
sf::Color mPathColor = mColors.Path;
//Create nodes
for(unsigned int y = 0; y < mMaze.getSize().y; ++y)
{
for(unsigned int x = 0; x < mMaze.getSize().x; ++x)
{
if(mMaze.getPixel(x, y) == mPathColor) //Current pixel is a path
{
bool bTop = false;
bool bBottom = false;
unsigned short nNeighbours = 0;
//Check surroundings of pixel
if(y != 0 && mMaze.getPixel(x, y - 1) == mPathColor)
{
bTop = true;
++nNeighbours;
}
if(y != mMaze.getSize().y - 1 && mMaze.getPixel(x, y + 1) == mPathColor)
{
bBottom = true;
++nNeighbours;
}
if(x != 0 && mMaze.getPixel(x - 1, y) == mPathColor)
{
++nNeighbours;
}
if(x != mMaze.getSize().x - 1 && mMaze.getPixel(x + 1, y) == mPathColor)
{
++nNeighbours;
}
//Decide if a node has to be created at that pixel
if(x == 0 || y == 0 || x == mMaze.getSize().x - 1 || y == mMaze.getSize().y - 1)
{
dijkstra::CNode mNode;
mNode.XPos = x;
mNode.YPos = y;
vGraph->push_back(mNode);
if(*mStart == 0)
{
*mStart = &vGraph->back();
++nExits;
}
else
{
*mEnd = &vGraph->back();
++nExits;
}
}
else if(nNeighbours == 2 && bTop != bBottom)
{
dijkstra::CNode mNode;
mNode.XPos = x;
mNode.YPos = y;
vGraph->push_back(mNode);
}
else if(nNeighbours > 2)
{
dijkstra::CNode mNode;
mNode.XPos = x;
mNode.YPos = y;
vGraph->push_back(mNode);
}
}
}
}
if(nExits != 2)
return false;
The CNode class:
struct SConnection
{
SConnection(CNode *To, unsigned int Distance);
CNode *To;
unsigned int Distance;
};
class CNode
{
public:
CNode();
std::vector<SConnection> Connections()const;
bool AddConnection(CNode *mTo, unsigned int nDistance);
bool AddConnection(const SConnection &mConnection);
bool RemoveConnection(CNode *mTo);
bool operator > (const CNode &rhs)const;
bool operator < (const CNode &rhs)const;
bool operator == (const CNode &rhs)const;
CNode* Addr();
bool Completed;
unsigned int DistanceTo;
CNode *PreviousNode;
unsigned int XPos, YPos;
private:
std::vector<SConnection> m_vConnections;
};
Implementation:
SConnection::SConnection(CNode *To, unsigned int Distance)
{
this->Distance = Distance;
this->To = To;
}
CNode::CNode()
:Completed(false), DistanceTo(std::numeric_limits<unsigned int>::max()), PreviousNode(0)
{
}
std::vector<SConnection> CNode::Connections() const
{
return m_vConnections;
}
bool CNode::AddConnection(CNode *mTo, unsigned int nDistance)
{
if(mTo == 0)
return false;
if(mTo == this)
return false;
for(auto &it : m_vConnections)
{
if(it.To == mTo)
return false;
}
m_vConnections.push_back({mTo, nDistance});
mTo->m_vConnections.push_back({this, nDistance});
return true;
}
bool CNode::AddConnection(const SConnection &mConnection)
{
return (AddConnection(mConnection.To, mConnection.Distance));
}
bool CNode::RemoveConnection(CNode *mTo)
{
for(auto it = m_vConnections.begin(); it != m_vConnections.end(); ++it)
{
if(it->To == mTo)
{
m_vConnections.erase(it);
for(auto it2 = mTo->m_vConnections.begin(); it2 != m_vConnections.end(); ++it2)
{
if(it2->To == this)
mTo->m_vConnections.erase(it2);
}
}
}
return false;
}
bool CNode::operator >(const CNode &rhs)const
{
return DistanceTo > rhs.DistanceTo;
}
bool CNode::operator <(const CNode &rhs) const
{
return DistanceTo < rhs.DistanceTo;
}
bool CNode::operator ==(const CNode &rhs)const
{
return DistanceTo == rhs.DistanceTo;
}
CNode *CNode::Addr()
{
return this;
}
Your main problem is here:
dijkstra::CNode mNode;
//...
vGraph->push_back(mNode);
if(*mStart == 0)
{
*mStart = &vGraph->back();
++nExits;
}
else
{
*mEnd = &vGraph->back();
++nExits;
}
}
else if(nNeighbours == 2 && bTop != bBottom)
{
dijkstra::CNode mNode;
//...
vGraph->push_back(mNode);
}
else if(nNeighbours > 2)
{
dijkstra::CNode mNode;
//...
vGraph->push_back(mNode);
}
Local variables are not placed in global heap, and can be forgotten by programm soon after the code block where they were created is finished.
The better way to improve your code is to rewrite function declaration as
bool CreateGraph(const sf::Image &mMaze, std::vector<dijkstra::CNode*> *vGraph, dijkstra::CNode **mStart, dijkstra::CNode **mEnd, SMazeCol mColors)
And inside function change all:
dijkstra::CNode mNode
vGraph->push_back(mNode);
to
std::shared_ptr<dijkstra::CNode> mNode =
std::shared_ptr<dijkstra::CNode>(new dijkstra::CNode(X, Y));
vGraph->push_back(mNode.get());
I'm working on an assignment for one of my CS courses. My professor wants us to implement a certain data structure using an array. I've been reviewing my code to see where I may be accessing outside of the vector's range, but I'm not seeing anything that I think is wrong.
When I run the test .cpp file, it only extracts one item before breaking.
Could someone point out any glaring mistakes in my code?
class minHeap {
private:
vector<int> nodes;
int current;
int parent(int i) {
return (i-1)/2;
}
int leftChild(int i) {
return 2*i+1;
}
int rightChild(int i) {
return 2*i+2;
}
void bubbleUp(int i) {
if(i > 0) {
int p = parent(i);
if(nodes[i] < nodes[p]) {
swap(nodes[i], nodes[p]);
bubbleUp(p);
}
}
}
void bubbleDown(int i) {
if(i < current) {
int a = leftChild(i);
int b = rightChild(i);
if(a <= current) {
if(nodes[i] > nodes[a] || nodes[i] > nodes[b]) {
if(nodes[a] < nodes[b]) {
swap(nodes[i], nodes[a]);
bubbleDown(a);
}
else {
swap(nodes[i], nodes[b]);
bubbleDown(b);
}
}
}
}
}
public:
minHeap() {
current = -1;
}
void insert(int x) {
current++;
nodes.push_back(x);
bubbleUp(current);
}
int extractMin() {
int min = nodes[0];
swap(nodes[0], nodes[current]);
current--;
nodes.pop_back();
bubbleDown(0);
return min;
}
bool empty() {
if(current < 0)
return true;
return false;
}
};
Update code
int parent(int i) {
int res = (i-1)/2;
if (!(res >= 0 && res <= current)) cout << "error: parent(" << i << ") out of index";
return res;
}
int leftChild(int i) {
int res = 2*i+1;
if (!(res >= 0 && res <= current)) cout << "error: leftChild(" << i << ") out of index";
return res;
}
int rightChild(int i) {
int res = 2*i+2;
if (!(res >= 0 && res <= current)) cout << "error: rightChild(" << i << ") out of index";
return res;
}
And you will see
error: rightChild(0) out of index1
when extracting min from heap of size 3. You need to take into account right child index in
if(a > current) {}
else {
if(nodes[i] > nodes[a] || nodes[i] > nodes[b]) {
I know that similar question has been asked,but I still can not figure out what is wrong.As mentioned above,I am debugging a program with VS2010 which always telling me "This may be due to a corruption of the heap, which indicates a bug in SwiftIndex.exe or any of the DLLs it has loaded...".So,here is part of my code:
Status PrefixQuickSI::my_QucikSI(std::vector<_QISymbol> &cur_sequence, QISequence graphcode, int depth, int feature_size, ECVector<char> cur_UsageTab, ECVector<SequenceIndex> cur_MappingTab, bool &flag)
{
Status st;
int vcnt = m_QueryGraph->V();
_QISymbol T;
if(depth == 0)
{
T.tSymbol = graphcode.sequence[depth]->tSymbol;
T.rSymbols.clear();
for(int i = 0; i < graphcode.sequence[depth]->numOfRSymbol; i++)
{
int v1,v2;
Label elabel;
v1 = graphcode.sequence[depth]->rSymbol[i].val;
v2 = graphcode.sequence[depth]->rSymbol[i+1].val;
elabel = graphcode.sequence[depth]->rSymbol[i].lable;
if(m_QueryGraph->getELabel(cur_MappingTab[v1],cur_MappingTab[v2]) != elabel)
{
flag = false;
return OK;
}
T.rSymbols.push_back(graphcode.sequence[depth]->rSymbol[i]);
T.rSymbols.push_back(graphcode.sequence[depth]->rSymbol[i+1]);
i++;
}
depth++;
cur_sequence.push_back(T);
if(depth == graphcode.numOfPrefixNode)
{
flag =true;
return OK;
}
else
{
st = my_QucikSI(cur_sequence, graphcode,depth, feature_size, cur_UsageTab, cur_MappingTab, flag);
if(flag == true)
{
return OK;
}
else
{
flag = false;
return OK;
}
}
}
else
{
T.tSymbol = graphcode.sequence[depth]->tSymbol;
for( int j = 0; j < graphcode.sequence[depth]->numOfRSymbol; ++j )
{
RSymbol rSymbol;
rSymbol = graphcode.sequence[depth]->rSymbol[j];
T.rSymbols.push_back(rSymbol);
}
int pV;
VertexIDSet Vcandiates;
for( int i = 0; i < vcnt; i++ )
{
pV = T.tSymbol.p;
if( cur_UsageTab[i] > 0 || m_QueryGraph->getLabel(i) != T.tSymbol.l || m_QueryGraph->getELabel(i, cur_MappingTab[pV]) != T.tSymbol.pl)
continue;
Vcandiates.insert(i);
}
for( VertexIDSet::const_iterator v = Vcandiates.begin(); v != Vcandiates.end(); v++ )
{
bool mis_match = false;
for( std::vector<RSymbol>::const_iterator r = T.rSymbols.begin(); r != T.rSymbols.end(); r++ )
{
if( !MatchREntry(cur_sequence, *v, *r) )
{
mis_match = true;
break;
}
}
if( mis_match )
continue;
cur_MappingTab[feature_size + depth] = *v;
cur_UsageTab[*v] = 1;
depth++;
cur_sequence.push_back(T);
if(depth == graphcode.numOfPrefixNode)
{
flag = true;
return OK;
}
else
{
st = my_QucikSI(cur_sequence, graphcode,depth, feature_size, cur_UsageTab, cur_MappingTab,flag);
if(flag == true)
{
return OK;
}
else
{
cur_UsageTab[*v] = 0;
depth--;
}
}
}
}
return OK;
}
and the calling function statement is:
int depth = 0;
st = my_QucikSI(cur_sequence, datacodes[cur_graphid], depth, cur_size,cur_UsageTab,cur_MappingTab, flag);
I have debugged step by step,and found that the "heap corruption" occurred in the second return of the recursion of function my_QuickSI(flag already equaled true at the third recursion and function returned to the second recursion,when it's about to return to the first recursion,the "heap corruption" happened).
Hope someone find where the problem is.
You can find my previous answer useful for your problem:
https://stackoverflow.com/a/22074401/2724703
In general heap corruption is often detected after the real corruption has already occurred by some DLL/module loaded within your process.
const int PIXEL_WIDTH = 10;
const int PIXEL_HEIGHT = 10;
const int WORLD_X = 64; //WORLD_X * PIXEL WIDTH = SCREEN_WIDTH if you want the world to be the same size as the screen
const int WORLD_Y = 64;
enum Pixel_Types {
AIR,
WALL,
DIRT,
STONE
};
class Pixel
{
int x, y;
bool affected_by_gravity;
Pixel_Types type;
public:
Pixel() : affected_by_gravity(false), type(AIR), x(0), y(0) {}
Pixel(int temp_x, int temp_y) : affected_by_gravity(false), type(AIR), x(temp_x), y(temp_y) {}
int getX() { return x; } //x is 0-63, scales up in the rendering code
int getY() { return y; } //y is 0-63, scales up in the rendering code
int getScreenX() { return x*PIXEL_WIDTH; } //x is 0-63, scales up in the rendering code
int getScreenY() { return y*PIXEL_HEIGHT; } //y is 0-63, scales up in the rendering code
bool setDeltaX(int temp_delta_x);
bool setDeltaY(int temp_delta_y);
void setAffectedByGravity(bool yesorno) { affected_by_gravity = yesorno; }
bool getAffectedByGravity() { return affected_by_gravity; }
Pixel_Types getType() { return type; }
void setType(Pixel_Types what_type) { type = what_type; }//if (type == DIRT or type == STONE) { affected_by_gravity = true; } }
};
std::vector<Pixel> world; //the world is a dynamically allocated thing
Pixel* getPixelFromCoordinates(int x, int y)
{
if (x > 63) x = 63;
else if (x < 0) x = 0;
if (y > 63) y = 63;
else if (y < 0) y = 0;
for (int pixel_index = 0; pixel_index < world.size(); pixel_index++) {
if (world.at(pixel_index).getX() == x && world.at(pixel_index).getY() == y) {
return &world.at(pixel_index);
}
}
return NULL;
}
bool Pixel::setDeltaX(int temp_delta_x) {
if (x+temp_delta_x > SCREEN_WIDTH/PIXEL_WIDTH or x+temp_delta_x < 0) {
return false;
}
if (getPixelFromCoordinates(x+temp_delta_x, y)->type == AIR) {
x += temp_delta_x;
return true;
}
return false;
}
bool Pixel::setDeltaY(int temp_delta_y) {
if (y+temp_delta_y > SCREEN_HEIGHT/PIXEL_HEIGHT or y+temp_delta_y < 0) {
return false;
}
if (getPixelFromCoordinates(x, y+temp_delta_y)->type == AIR) {
y += temp_delta_y;
return true;
}
return false;
}
void generateWorld()
{
for (int world_generation_index = 0; world_generation_index < 4096; world_generation_index++) {
int x = world_generation_index % WORLD_X; //the world is 64 pixels left and right, and 64 up and down. this math is pretty easy and just extrapolates that. also each pixel is 10 pixels across, times 64 pixels = 640 (the resolution)
int y = floor(world_generation_index / WORLD_Y); //both x and y start at 0
world.push_back(Pixel(x, y));
if (x == 0 || x == 63) {
world.at(world_generation_index).setType(WALL);
}
if (y == 1) {
world.at(world_generation_index).setType(WALL);
}
}
std::cout << "World size: " << world.size() << std::endl;
}
void createPixel(int x, int y, Pixel_Types type)
{
std::cout << x << std::endl;
std::cout << y << std::endl << std::endl;
y = (SCREEN_HEIGHT / PIXEL_HEIGHT) - y; //compensate for the stupid inverted y in opengl
//if (getPixelFromCoordinates(x, y)->getType() == AIR) {
getPixelFromCoordinates(x, y)->setType(type);
//}
}
void physicsOneStep()
{
for (int pixel_index = 0; pixel_index < world.size(); pixel_index++) {
if (world.at(pixel_index).getType() == DIRT or world.at(pixel_index).getType() == STONE) {//if (world.at(pixel_index).getAffectedByGravity()) {
world.at(pixel_index).setDeltaY(-1);
//std::cout << world.at(pixel_index).getX() << std::endl;
//std::cout << world.at(pixel_index).getY() << std::endl << std::endl;
}
}
}
So when I try to run this code (part of a larger project) it occasionally gives me a Segfault on calling setType(DIRT) from within createPixel(). I know that the values provided to createPixel() are within the range that they are allowed to be (0 to 64). It seems to segfault if you click (which calls createPixel()) in the same spot twice. The line that the debugger says segfaults is
void setType(Pixel_Types what_type) { type = what_type; }
though, I've verified that the values that I have supplied to this are correct.
Since there is no dynamic allocation inside the class, having a segfault on such an allocation most certainly occur because the this pointer itself is incorrect (NULL or badly allocated). You should get up the traceback when it segfaulted to see how the object on which you called setType was allocated. For example, shouldn't the line
world.push_back(Pixel(x, y));
be
world.push_back(new Pixel(x,y));
?
I'm having a really bad time here looking for the error in my code.
My collision detection won't work here even the algorithm I searched in Google.
void PollEvents()
{
for (int i = 0;i < NUMBER_OF_BLOCKS; ++i)
{
Rectangle& a = blocks[i];
if (mouse.state == GLFW_PRESS)
{
//look for any block to grab
if (mouse.leftClick && !blocks[selectedBlock].Grab() &&
a.Hover(mouse.pos.x, mouse.pos.y))
{
//prevent grabbing another block
if (i != selectedBlock) {
selectedBlock = i;
}
a.Grab() = true;
if (a.IsTypeHorizontal()) {
diff = mouse.pos.x - a.Left();
} else {
diff = mouse.pos.y - a.Top();
}
}
if (a.Grab())
{
for (int j = 0;j < NUMBER_OF_BLOCKS; ++j)
{
//skip for any self-checking
if (i == j) continue;
Rectangle& b = blocks[j];
//check for rectangle collision
if (!a.Collide(b) || b.Collide(a)) {
//j++;
//how does this block will move.
if (a.IsTypeVertical()) {
a.SetY(mouse.pos.y - diff);
} else {
a.SetX(mouse.pos.x - diff);
}
} else {
switch (a.sideHit)
{
case UP:
//a.SetY(b.Bottom());
printf("UP\n");
break;
case DOWN:
//a.SetY(b.Top() + a.GetHeight());
printf("DOWN\n");
break;
case LEFT:
//a.SetX(b.Right());
printf("LEFT\n");
break;
case RIGHT:
//a.SetX(b.Left() - a.GetWidth());
printf("RIGHT\n");
break;
}
}
//check for bound collision
a.BoundCheck(1.f);
}
}
} else {
a.Grab() = false;
}
}
}
Collision detection:
bool Rectangle::Collide(const Rectangle& r) {
if (IsTypeHorizontal()) {
if (r.Hover(Left(), Top()) && r.Hover(Right(), Top())) {
sideHit = UP;
return true;
} else if (r.Hover(Right(), Bottom()) && r.Hover(Left(), Bottom())) {
sideHit = DOWN;
return true;
}
// } else if (r.Hover(Left(), Top())) {
// sideHit = UP;
// return true;
// } else if (r.Hover(Right(), Top())) {
// sideHit = UP;
// return true;
// } else if (r.Hover(Right(), Bottom())) {
// sideHit = DOWN;
// return true;
// } else if (r.Hover(Left(), Bottom())) {
// sideHit = DOWN;
// return true;
// }
} else {
if (r.Hover(Left(), Top()) && r.Hover(Left(), Bottom())) {
sideHit = LEFT;
return true;
} else if (r.Hover(Right(), Top()) && r.Hover(Right(), Bottom())) {
sideHit = RIGHT;
return true;
}
// } else if (r.Hover(Left(), Top())) {
// sideHit = LEFT;
// return true;
// } else if (r.Hover(Left(), Bottom())) {
// sideHit = LEFT;
// return true;
// } else if (r.Hover(Right(), Top())) {
// sideHit = RIGHT;
// return true;
// } else if (r.Hover(Right(), Bottom())) {
// sideHit = RIGHT;
// return true;
// }
}
return false;
}
Code for Hover:
inline float Hover(float X, float Y) const {
return X >= Left() &&
X <= Right() &&
Y >= Bottom() &&
Y <= Top();
}
I'm trying to make my own unblockme.
Please help me on my collision-detection. It's been 3 days now since I got stuck in this problem.
UPDATE
I have found out the problem why all rect-rect collision detection won't work in my program.
Bug:
if (!a.Collide(b)) {
//Move()
} else {
//Resolve collision
}
This one should be
if (!Rectangle::Collide(a, b)) {
//Move()
} else {
//Resolve collision
}
Making the Collide() a static member of Rectangle because, as you can see in my implementation of Collide(), it bases its decision on its own member so a.Hover(b.x, b.y) doesn't make any sense.
Hope this helps a little bit to all newbies like me.
To do rect/rect collision detection, if any of one (edges parallel to x and y axis) rect's four points is inside the other rect, we have a collision.
An easier way than to check each of the four points is to check if one X edge is between both the other rect's X edges, and if one Y edge is between both the other rect's Y edges - if both are true, we have a collision (because the two edges must meet at a point inside of the other rect). So we just check this in both directions:
bool isclamped(float mid, float A, float B)
{
if (A > B)
{
return mid >= B && mid <= A;
}
return mid >= A && mid <= B;
}
bool checkcollisiononeway(rect rectA, rect rectB)
{
if (isclamped(rectA.left, rectB.left, rectB.right)
|| isclamped(rectA.right, rectB.left, rectB.right))
&& (isclamped(rectA.bottom, rectB.bottom, rectB.top)
|| isclamped(rectA.top, rectB.bottom, rectB.top))
{
return true;
}
return false;
}
bool checkcollisionbothways(rect rectA, rect rectB)
{
return checkcollisiononeway(rectA, rectB) || checkcollisiononeway(rectB, rectA);
}
To determine the angle of collision after detecting a collision, find the angle between their two centers using atan2(rectA.y - rectB.y, rectA.x - rectB.x) (the angle is returned in radians, not in degrees)