C++ C++;-将指向非POD的指针推送到优先级队列导致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 <

我正在尝试实现一个使用a*算法的4x4滑块谜题解算器。尽管我们试图以尽可能简洁的方式编写代码,但代码中还是出现了一个segfault,它指向将指针推送到
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();