使用 *this 时出现段错误

发布于 2024-10-14 06:53:53 字数 2600 浏览 2 评论 0原文

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

我有 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) {}
};

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

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

I'm getting a segfault when I try to access a member of a class from within a method of that same class, which does not make sense to me at all.

I have the Tree class:

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]);
                }
            }
        }
    }
}

...and the Coord class...

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;
}

... and the Loc class, from which Coord inheirits...

class Loc
{
    public:
        int x, y;

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

The segfault occurs in Coord::getValidMoves() as indicated by the comments. If step through the code to that point, then make a watch for *this or x or this->x, I get a "Cannot access memory at 0xbaadf00d"

Why is this happening? Where have I messed up? I just don't understand how trying to access *this in a method could possibly result in a segfault.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

小巷里的女流氓 2024-10-21 06:53:53

您需要初始化 Coord::children 的元素。它们不保证为 NULL,因此在 populateTree() 中,当您对每个子项进行 null 测试时,您将得到非 null 子项,尽管它们不会指向有效的 坐标。当它们从队列中弹出时,您对无效的Coord调用getValidMoves(),您将得到段错误。

Coord 构造函数更改为:(

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

您需要为 std::fill 添加 #include

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

You need to initialise the elements of Coord::children. They aren't guaranteed to be NULL, so in populateTree(), when you do the null test on each child, you will get non-null children although they will not point to a valid Coord. When they are popped off the queue, and you call getValidMoves() on the invalid Coord you'll get the seg-fault.

Change the Coord constructor to:

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

(you'll need to #include <algorithm> for std::fill.

Note that the segfault occurs on the attempt to dereference this because that's the first time you try to access the invalid memory.

沦落红尘 2024-10-21 06:53:53

当对无效(或失效)指针调用方法时,访问数据成员时出现段错误是一个常见问题。虽然该语言提供了对象和方法的抽象,但底层实现仍然具有函数和数据,其中方法是应用于数据的函数(代码)(隐式 *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] 的行处检测到

A segfault when accessing data members is a common problem when a method is called on an invalid (or invalidated) pointer. While the language provides the abstraction of objects and methods, the underlying implementation still has functions and data, where methods are functions (code) that applies to an data (implicit *this).

Check that the pointers are valid (not null, not freed) before calling the method, as that is surely the problem:

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)
}

In the code above, all errors will most be detected at the line marked as [1]

瑾夏年华 2024-10-21 06:53:53

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

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->children[i] != NULL 也不会为真。然后,您将调用这些不存在的子函数的成员函数,并且当这些成员函数运行时,它们将具有无效的 this 指针。

If you make your constructor look like this:

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

your problem will go away. You should initialize all your data members in the constructor.

The problem is that children will contain random data. It won't be initialized to NULL, and so the test currnode->children[i] != NULL will not be true even for non-existent children. You will then call member functions on these non-existent children and when those member functions run they will have an invalid this pointer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文