【问题标题】:Segfault when using *this使用 *this 时的段错误
【发布时间】:2011-01-22 00:05:07
【问题描述】:

当我尝试从同一个类的方法中访问一个类的成员时,我遇到了段错误,这对我来说根本没有意义。

我有 Tree 类:

class Tree
{

public:

Coord* root;

Tree(int x, int y)
{
    root = new Coord(x, y);
    populateTree();
}

void populateTree()
{
    queue<Coord*> nodes;
    nodes.push(root);

    while (nodes.size() > 0)
    {
        Coord* currnode = nodes.front();
        nodes.pop();

        if ( !(currnode->getValidMoves()) )
        {
            return;
        }

        else
        {
            for (int i = 0; i < MAX_CHILDREN_PER_COORD; i++)
            {
                if (currnode->children[i] != NULL)
                {
                    nodes.push(currnode->children[i]);
                }
            }
        }
    }
}

...和 ​​Coord 类...

class Coord : public Loc
{
    public:

    Coord(int xPos, int yPos);

    Coord* children[MAX_CHILDREN_PER_COORD];


    bool getValidMoves();


    bool operator==(Coord coord);
    bool operator==(Loc loc);

};

Coord::Coord(int xPos, int yPos) : Loc(xPos, yPos) {}


bool Coord::getValidMoves()
{
    //This line segfaults
    Coord test = *this;

    //Global boolean method. Checks found
    if (!foundTrue())
    {
        for (int i = 0; i < MAX_CHILDREN_PER_COORD; i++)
        {
            //If the above segfaulting line is commented out, this is the first place that segfaults
            int newX = x + knightPositions[i].x;
            int newY = y + knightPositions[i].y;

            if ( !(newX > GRID_X || newX < 0 || newY > GRID_Y || newY < 0) )
            {
                //knightPositions is a Loc array of length MAX_CHILDREN_PER_COORD
                children[i] = new Coord(x + knightPositions[i].x, y + knightPositions[i].y);
                //Global 2d array of ints. Gets checked by foundTrue()
                found[x + knightPositions[i].x][y + knightPositions[i].y] = true;
            }
        }

        return true;
    }

    else
    {
        return false;
    }

    //Otherwise, just leave it as a blank array
}


bool Coord::operator==(Coord coord)
{
    return coord.x == x && coord.y == y;
}

bool Coord::operator==(Loc loc)
{
    return loc.x == x && loc.y == y;
}

... 以及 Coord 继承的 Loc 类...

class Loc
{
    public:
        int x, y;

        //Constructor
        Loc(int xPos, int yPos) : x(xPos), y(yPos) {}
};

如 cmets 所示,段错误发生在 Coord::getValidMoves() 中。如果单步执行代码到该点,然后监视 *this 或 x 或 this->x,我会得到“无法在 0xbaadf00d 访问内存”

为什么会这样?我哪里搞砸了?我只是不明白如何尝试在方法中访问 *this 可能会导致段错误。

【问题讨论】:

  • 当您的对象正在执行其方法之一时,是否有其他东西(另一个线程或同一线程中的古怪回调)删除您的对象?
  • 你开启优化了吗?
  • 附带说明,您正在为具有(未初始化的)指针成员但没有复制 ctor 的类在多个位置(Coord test = *this;bool Coord::operator==(Coord coord))复制Coord (或赋值操作或析构函数)。
  • @Eugen:是的,这是一个旧编程竞赛的练习题,所以我根本不关心良好的编程练习。只要它吐出正确的答案:D

标签: c++ debugging segmentation-fault


【解决方案1】:

你需要初始化Coord::children的元素。它们不能保证为 NULL,因此在populateTree() 中,当您对每个孩子进行空测试时,您将获得非空孩子,尽管它们不会指向有效的Coord。当他们从队列中弹出,并且您在无效的 Coord 上调用 getValidMoves() 时,您将得到 seg-fault。

Coord 构造函数更改为:

Coord::Coord(int xPos, int yPos) : Loc(xPos, yPos)
{
    std::fill( children, children + MAX_CHILDREN_PER_COORD, NULL );
}

(对于std::fill,您需要#include &lt;algorithm&gt;

请注意,尝试取消引用 this 时会发生段错误,因为这是您第一次尝试访问无效内存。

【讨论】:

  • 修复它。非常感谢!
【解决方案2】:

访问数据成员时的段错误是在无效(或无效)指针上调用方法时的常见问题。虽然语言提供了对象和方法的抽象,但底层实现仍然具有函数和数据,其中方法是应用于数据的函数(代码)(隐式 *this)。

在调用方法之前检查指针是否有效(不为空,未释放),因为这肯定是问题所在:

struct test {
   int x;
   void foo( int y ) {
      x = y;       // [1]
   }
};
int main() {
   test *p = 0;
   //p->foo();     // segfault in x=y above: this == 0
   p = new test;
   p->foo();
   delete p;
   // p->foo();    // undefined behavior, can be a segfault or not
   p = reinterpret_cast<test*>( "This is a literal" );
   p->foo();       // undefined behavior, probably segfault
                   // writing to read-only memory (this depends on compiler/environment)
}

在上面的代码中,所有错误都将在标记为 [1] 的行中检测到

【讨论】:

    【解决方案3】:

    如果你让你的构造函数看起来像这样:

    Coord::Coord(int xPos, int yPos) : Loc(xPos, yPos)
    {
        for (int i = 0; i < MAX_CHILDREN_PER_COORD; ++i) {
            children[i] = NULL;
        }
    }
    

    您的问题将会消失。您应该在构造函数中初始化所有数据成员。

    问题是children 将包含随机数据。它不会被初始化为NULL,因此即使对于不存在的孩子,测试currnode-&gt;children[i] != NULL 也不会为真。然后,您将对这些不存在的子函数调用成员函数,当这些成员函数运行时,它们将有一个无效的 this 指针。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-12
      • 2017-08-02
      • 2010-10-07
      • 2021-07-03
      • 2011-11-29
      • 2020-01-28
      • 1970-01-01
      相关资源
      最近更新 更多