C++ C++;-将指向非POD的指针推送到优先级队列导致segfault?
我正在尝试实现一个使用a*算法的4x4滑块谜题解算器。尽管我们试图以尽可能简洁的方式编写代码,但代码中还是出现了一个segfault,它指向将指针推送到C++ C++;-将指向非POD的指针推送到优先级队列导致segfault?,c++,segmentation-fault,priority-queue,a-star,C++,Segmentation Fault,Priority Queue,A Star,我正在尝试实现一个使用a*算法的4x4滑块谜题解算器。尽管我们试图以尽可能简洁的方式编写代码,但代码中还是出现了一个segfault,它指向将指针推送到std::priority_队列实例的失败尝试。以下是调试尝试后的完整代码,我不知道如何将其剪切到一个工作测试用例中: #include <iostream> #include <iomanip> #include <cstring> #include <cmath> #include <
std::priority_队列
实例的失败尝试。以下是调试尝试后的完整代码,我不知道如何将其剪切到一个工作测试用例中:
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cmath>
#include <vector>
#include <set>
#include <queue>
#include <functional>
#include <ctime>
#include <cstdlib>
using namespace std;
const char GOAL_STATE[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};
class Puzzle
{
protected:
char puzzle[16];
int index(char searched) const
{
for(int i=0; i<16; i++)
{
if (puzzle[i]==searched)
return i;
}
return -1;
}
public:
Puzzle(const char init[16] = NULL)
{
if(init!=NULL)
{
memcpy(puzzle, init, sizeof(char)*16);
}
else
{
memcpy(puzzle, GOAL_STATE, sizeof(char)*16);
}
}
void show() const
{
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
{
cout << setw(3) << (int)puzzle[i*4+j] << " ";
}
cout << endl;
}
}
bool move(int m_pos)
{
int b_pos = index(0);
int b_x = b_pos / 4;
int b_y = b_pos % 4;
int x = m_pos / 4;
int y = m_pos % 4;
if (m_pos < 16 && (
(x == b_x && (y == b_y + 1 || y == b_y - 1)) ||
(y == b_y && (x == b_x + 1 || x == b_x - 1))
)
)
{
char tmp = puzzle[m_pos];
puzzle[m_pos] = puzzle[b_pos];
puzzle[b_pos] = tmp;
return true;
}
else
return false;
}
int count_correct() const
{
int ret = 0;
for(int i=0; i<16; i++)
if ((i<15 && (puzzle[i])==i+1) || (i==15 && puzzle[i]==0))
ret++;
return ret;
}
vector<int> possible_moves() const
{
vector<int> ret;
int b_pos = index(0);
int b_x = b_pos / 4;
int b_y = b_pos % 4;
ret.push_back(b_y * 4 + b_x - 1);
ret.push_back((b_y - 1) * 4 + b_x);
if (b_x<3)
ret.push_back(b_y * 4 + b_x + 1);
if (b_y<3)
ret.push_back((b_y + 1) * 4 + b_x);
return ret;
}
};
class AStarPuzzle : public Puzzle
{
int H;
int f;
public:
int tried;
AStarPuzzle* previous;
AStarPuzzle(const char init[16] = NULL,
int _f = 0, int _tried = 0, AStarPuzzle* _previous = NULL) : Puzzle(init)
{
f = _f;
tried = _tried;
previous = _previous;
}
AStarPuzzle (const AStarPuzzle& old) : Puzzle(old.puzzle)
{
f = old.f;
tried = old.tried;
previous = old.previous;
}
double heur() const
{
double ret = 0.0;
for (int goalIndex = 0 ; goalIndex<16; goalIndex++)
{
int tileIndex = index( GOAL_STATE[goalIndex] );
ret += abs((double)((goalIndex % 4) - (tileIndex % 4)));
ret += abs(floor(goalIndex / 4.0) - floor(tileIndex / 4.0));
}
return 0.1*f + max(ret, (double)count_correct());
}
bool operator<(const AStarPuzzle& other) const
{
return heur()>other.heur();
}
int get_f()
{
return f;
}
void increase_f()
{
f++;
}
AStarPuzzle operator=(const AStarPuzzle& rhs)
{
cout << "STUB: AStarPuzzle::operator=" << endl;
}
~AStarPuzzle()
{
cout << "STUB: AStarPuzzle::~AStarPuzzle" << endl;
}
void operator delete(void *p)
{
cout << "Attempting to delete AStarPuzzle?" << endl;
}
};
struct CompareHeuristics : public std::binary_function<AStarPuzzle*, AStarPuzzle*, bool >
{
bool operator()(AStarPuzzle* lhs, AStarPuzzle* rhs) const
{
return lhs->heur() > rhs->heur();
}
};
vector<int> retracePath(AStarPuzzle* c)
{
vector<int> ret;
while (c->previous!=NULL)
{
c = c->previous;
ret.push_back(c->tried);
}
return ret;
}
vector<int> aStar(AStarPuzzle* current)
{
set<AStarPuzzle*> openList;
set<AStarPuzzle*> closedList;
std::priority_queue<AStarPuzzle*, std::vector<AStarPuzzle*>, CompareHeuristics> openHeap;
int max_corr = 0;
int min_step = 0;
openList.insert(current);
openHeap.push(current);
while (openList.size()!=0)
{
current = openHeap.top();
cout << "An iteration. heur()==" << current->heur() << endl;
current->show();
openHeap.top();
if (current->count_correct() == 16)
{
//return vector<int>();
return retracePath(current);
}
openList.erase(current);
closedList.insert(current);
vector<int> directions = current->possible_moves();
for(unsigned int i=0; i<directions.size(); i++)
{
AStarPuzzle* tile = new AStarPuzzle(*current);
tile->move(directions[i]);
tile->increase_f();
if (closedList.count(tile)==0)
{
int corr = tile->count_correct();
int f = tile->get_f();
if (corr > max_corr or (corr == max_corr && f < min_step))
{
max_corr = corr;
min_step = f;
cout << corr << "," << f << endl;
}
tile->previous = current;
if (openList.count(tile)==0)
{
openList.insert(tile);
openHeap.push(tile);
}
}
}
}
return vector<int>();
}
int main(int argc, char **argv) {
char shuffled[16];
memcpy(shuffled, GOAL_STATE, sizeof(char)*16);
srand(time(0));
for (int i=0; i<16; i++) {
int r = i + (rand() % (16-i));
char temp = shuffled[i];
shuffled[i] = shuffled[r];
shuffled[r] = temp;
}
shuffled = {0, 3, 7, 5, 9, 12 , 13 , 11, 8, 6 , 14, 4 , 15, 2 , 10 , 1 };
AStarPuzzle* p = new AStarPuzzle(shuffled);
p->show();
aStar(p);
return 0;
}
您忘记在
AStarPuzzle::operator=
中返回值。然后,但是超时。也许你应该在继续之前纠正无限循环。。。另外,您在Puzzle::move
中为m_pos
使用int
,并且您没有检查负值。改为使用无符号整数
编辑:在Visual C++ 2010上进行测试,无分段、无限循环。您应该检查是否使用了正确的运行时。
您在这里使用的是有符号整数算术vector<int> possible_moves() const
{
vector<int> ret;
int b_pos = index(0);
int b_x = b_pos / 4;
int b_y = b_pos % 4;
ret.push_back(b_y * 4 + b_x - 1);
ret.push_back((b_y - 1) * 4 + b_x);
if (b_x<3)
ret.push_back(b_y * 4 + b_x + 1);
if (b_y<3)
ret.push_back((b_y + 1) * 4 + b_x);
return ret;
}
向量可能移动()常量
{
向量ret;
int b_pos=索引(0);
int b_x=b_位置/4;
int b_y=b_位置%4;
后推(b_y*4+b_x-1);
向后推回((b_y-1)*4+b_x);
如果(b_x问题实际上与内存无关,那么正如@Synxis指出的那样,负m_pos被传递给Puzzle::move。发生这种情况的原因是可能的_moves()没有考虑到0块位于(0,0)中时的情况-修复可能的_移动有帮助。另一个错误与x和y相反,openHeap.top()被调用两次而不是openHeap.top(),openHeap.pop()有关.使用valgrind。这将帮助您找到错误。添加了valgrind输出。AStarPuzzle::operator=
从未被调用。是的,你是对的。但是我看到了很多问题都是由于缺少return语句造成的,所以我更愿意将其放在答案中。你是正确的,但我认为unsigned
不会解决这个问题。我认为po可能的移动
也需要检查b\U x>0
和b\U y>0
。带有负索引的访问发生在move()
,而不是您指出的地方。@gnome使用unsinged
强制我们重新检查内容。(.1)U
用作地址会带来更多麻烦。
> valgrind ./si-proj2cpp
==26655== Memcheck, a memory error detector
==26655== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==26655== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==26655== Command: ./si-proj2cpp
==26655==
0 3 7 5
9 12 13 11
8 6 14 4
15 2 10 1
An iteration. heur()==44
0 3 7 5
9 12 13 11
8 6 14 4
15 2 10 1
==26655== Invalid read of size 1
==26655== at 0x804950E: Puzzle::move(int) (main.cpp:74)
==26655== by 0x8048F3A: aStar(AStarPuzzle*) (main.cpp:231)
==26655== by 0x8049272: main (main.cpp:275)
==26655== Address 0x42ca1ef is 1 bytes before a block of size 32 alloc'd
==26655== at 0x402471C: operator new(unsigned int) (vg_replace_malloc.c:255)
==26655== by 0x8048EF6: aStar(AStarPuzzle*) (main.cpp:230)
==26655== by 0x8049272: main (main.cpp:275)
==26655==
==26655== Invalid write of size 1
==26655== at 0x8049525: Puzzle::move(int) (main.cpp:75)
==26655== by 0x8048F3A: aStar(AStarPuzzle*) (main.cpp:231)
==26655== by 0x8049272: main (main.cpp:275)
==26655== Address 0x42ca1ef is 1 bytes before a block of size 32 alloc'd
==26655== at 0x402471C: operator new(unsigned int) (vg_replace_malloc.c:255)
==26655== by 0x8048EF6: aStar(AStarPuzzle*) (main.cpp:230)
==26655== by 0x8049272: main (main.cpp:275)
==26655==
An iteration. heur()==44
0 3 7 5
9 12 13 11
8 6 14 4
15 2 10 1
An iteration. heur()==44
0 3 7 5
9 12 13 11
8 6 14 4
15 2 10 1
(...looks like an infinite loop, so I'm stopping the program with ctr+c)
0 3 7 5
9 12 13 11
8 6 14 4
15 2 10 1
^CAn iteration. heur()==44
==26655==
==26655== HEAP SUMMARY:
==26655== in use at exit: 17,076 bytes in 579 blocks
==26655== total heap usage: 805 allocs, 226 frees, 21,156 bytes allocated
==26655==
==26655== LEAK SUMMARY:
==26655== definitely lost: 0 bytes in 0 blocks
==26655== indirectly lost: 0 bytes in 0 blocks
==26655== possibly lost: 0 bytes in 0 blocks
==26655== still reachable: 17,076 bytes in 579 blocks
==26655== suppressed: 0 bytes in 0 blocks
==26655== Rerun with --leak-check=full to see details of leaked memory
==26655==
==26655== For counts of detected and suppressed errors, rerun with: -v
==26655== ERROR SUMMARY: 288 errors from 2 contexts (suppressed: 19 from 8)
vector<int> possible_moves() const
{
vector<int> ret;
int b_pos = index(0);
int b_x = b_pos / 4;
int b_y = b_pos % 4;
ret.push_back(b_y * 4 + b_x - 1);
ret.push_back((b_y - 1) * 4 + b_x);
if (b_x<3)
ret.push_back(b_y * 4 + b_x + 1);
if (b_y<3)
ret.push_back((b_y + 1) * 4 + b_x);
return ret;
}
vector<int> directions = current->possible_moves();
for(unsigned int i=0; i<directions.size(); i++)
{
AStarPuzzle* tile = new AStarPuzzle(*current);
tile->move(directions[i]); // <<------ here, line 231
tile->increase_f();