C++可执行文件在运行时冻结

发布于 2024-09-30 01:06:11 字数 6067 浏览 9 评论 0原文

我编写了一个简单的控制台程序,用于测试我正在构建的库中的一些关键类。现在,代码可以正确构建,没有错误。但是,执行代码后,我发现应用程序在代码中的某个点调用 Index 方法后停止工作。我尝试调试几种不同的方法来获取有关该问题的更多信息,但我收集的信息根本没有帮助我。也许它会帮助那些知道我没有做什么(或做得不正确)的人。

这是 Util 命名空间的内容;

    template<typename var>
class VectorNode
{
    public:
    VectorNode(var value, VectorNode<var>* next = NULL, VectorNode<var>* prev = NULL)
    {
        data = value;
        t_next = next;
        t_prev = prev;
    }
    ~VectorNode()
    {
        if (t_next != NULL)
            delete t_next;
    }


    virtual VectorNode<var>* Next(){ return t_next; } // get the next node in line
    virtual void Next(VectorNode<var>* newNode){ t_next = newNode; } // set the next node in line

    virtual VectorNode<var>* Prev(){ return t_prev; }// get the previous node in line
    virtual void Prev(VectorNode<var>* newNode){ t_prev = newNode; } // set the previous node in line

    virtual var Value(){ return data; } // get the node's value

    private:
    var data;
    VectorNode<var>* t_next;
    VectorNode<var>* t_prev;
};

template<typename var>
class Vector
{
    public:
    Vector()
    {
        tailNode = new VectorNode<var>(*(new var));
        headNode = new VectorNode<var>(*(new var), tailNode);
        tailNode->Prev(headNode);
        size = new int;
        *size = 0;
    }
    ~Vector()
    {
        delete headNode;
        delete size;
    }


    int Size(){ return *size; } // get the size of a vector
    void Add(var toAdd, int index = 0) // 
    {
        VectorNode<var>* lastNode;
        if (index > (*size))
            index = *size;
        if (index < 1) // add to the end of the vector
        {
            lastNode = tailNode;
        }
        else
        {
            int i;
            if (index <= (*size / 2)) // if the index is less than half the size, iterate forwards
            {
                lastNode = headNode;
                for (i = 1; i <= index; i++){ lastNode = lastNode->Next(); }
            }
            else // otherwise, iterate backwards
            {
                lastNode = tailNode;
                for (i = *size; i >= index; i--){ lastNode = lastNode->Prev(); }
            }
        }
        VectorNode<var>* temp = lastNode->Prev();
        VectorNode<var>* newNode = new VectorNode<var>(toAdd, lastNode, temp);
        lastNode->Prev(newNode);
        temp->Next(newNode);
        *size = *size + 1;
    }
    void Remove(int index) // remove an index
    {
        VectorNode<var>* toRemove;
        VectorNode<var>* lastNode;
        int i;
        if ((index > *size) || (index < 1)) // if not in the domain...
            index = *size;
        if (index <= (*size / 2)) // iterate forwards
        {
            lastNode = headNode;
            for (i = 1; i < index+2; i++){ lastNode = lastNode->Next(); }
        }
        else // iterate backwards
        {
            lastNode = tailNode;
            for (i = *size; i > index; i--){ lastNode = lastNode->Prev(); }
        }
        toRemove = lastNode->Prev();
        VectorNode<var>* temp = toRemove->Prev();
        temp->Next(lastNode);
        lastNode->Prev(temp);
        delete toRemove;
        *size = *size - 1;
    }
    var Index(int index) // get the value of a node
    {
        VectorNode<var>* lastNode;
        int i;
        if (index <= (*size / 2)) // iterate forwards
        {
            lastNode = headNode;
            for (i = 1; i <= index; i++){ lastNode = lastNode->Next(); }
        }
        else // iterate backwards
        {
            lastNode = tailNode;
            for (i = *size; i >= index; i--){ lastNode = lastNode->Prev();}
        }
        return lastNode->Value();
    }

    private:
    int* size;
    VectorNode<var>* tailNode; // the head and tail nodes are placeholders, to keep the list inside its boundaries
    VectorNode<var>* headNode;
};

如果您不想阅读,我用注释标记了每个方法,解释了其总体目的。另外,我尝试添加一些代码块的小解释。

并且,这是入口函数和包含内容;

<代码>

#include "iostream"

#include "stdlib.h" // this has nothing in it that's being used
#include "testhead.h" // the location of the Util namespace

int main() { 使用命名空间 Util;

Vector<int>* x = new Vector<int>();
x->Add(42);
x->Add(24);
x->Add(12);
x->Add(21);
std::cout << "Listing Indices\n";
for (int i = 1; i <= x->Size(); i++)
{
    std::cout << i << "\t" << x->Index(i) << "\n";
}
std::cout << "Size(pre-removal):\t" << x->Size() << "\n";
x->Remove(2);
std::cout << "Size(post-removal):\t" << x->Size() << "\n";
std::cout << "Listing Indices\n";
std::cout << 3 << "\t" << x->Index(3) << "\n";
for (int i = 1; i <= x->Size(); i++)
{
    std::cout << i << "\t" << x->Index(i) << "\n";
}
system("Pause");

}

好吧,我得到的结果是这样的。在使用Remove方法之前,可以从Vector类中自由访问任何索引。但是,使用remove方法后,无论删除哪个索引,都无法访问第一个以上的索引。除非我们删除第一个索引,否则无法访问任何索引。我尝试单步执行代码,但它把我带到了索引方法中的这行代码;

else
{
lastNode = tailNode;
for (i = *size; i >= index; i--){ lastNode = lastNode->Prev();} // error occurs after running this line
}

现在,由于我能够找出导致问题的删除方法,我返回并得到了一些有关该问题的输出。我让它在完成执行之前运行以下行两次。删除 toRemove 之前一次,删除之后再一次。

std::cout << (lastNode->Prev() == temp) << "\t" << (temp->Next() == lastNode) << "\n";

在被删除之前,它打印 1 两次,表明比较是正确的。但是,当我第二次调用 Prev 和 Next 方法时,程序就会冻结。我知道这是因为我释放了内存中的位置,但比较显示其他节点对我删除的节点的任何引用都消失了。现在,我的具体问题是为什么会造成这种情况,以及如何解决它?我对管理堆上的内存有一点了解,但这似乎不会导致程序出现任何问题。因此,如果有人愿意提供的话,我可以用一个简短的解释来解释为什么会发生这种情况。

如果有任何帮助,我正在使用 Code::Blocks IDE 和 GNU GCC 编译器。另外,请告诉我我是否做错了与我提出问题的方式相关的问题。我不经常访问 Stack Overflow,也不会在这里提问。据我所知,这是回答您的问题的最佳场所。

I wrote a simple console program for the use of testing some key classes in a library I'm building. Now, the code builds correctly with no errors. But, after executing the code, I found that the application stops working after calling the Index method at a certain point in the code. I tried debugging a few different ways to get more information about the problem, but the information I gathered didn't help me at all. Maybe it will help someone else who knows what I'm not doing(or doing incorrectly).

Here's the contents of the Util namespace;

    template<typename var>
class VectorNode
{
    public:
    VectorNode(var value, VectorNode<var>* next = NULL, VectorNode<var>* prev = NULL)
    {
        data = value;
        t_next = next;
        t_prev = prev;
    }
    ~VectorNode()
    {
        if (t_next != NULL)
            delete t_next;
    }


    virtual VectorNode<var>* Next(){ return t_next; } // get the next node in line
    virtual void Next(VectorNode<var>* newNode){ t_next = newNode; } // set the next node in line

    virtual VectorNode<var>* Prev(){ return t_prev; }// get the previous node in line
    virtual void Prev(VectorNode<var>* newNode){ t_prev = newNode; } // set the previous node in line

    virtual var Value(){ return data; } // get the node's value

    private:
    var data;
    VectorNode<var>* t_next;
    VectorNode<var>* t_prev;
};

template<typename var>
class Vector
{
    public:
    Vector()
    {
        tailNode = new VectorNode<var>(*(new var));
        headNode = new VectorNode<var>(*(new var), tailNode);
        tailNode->Prev(headNode);
        size = new int;
        *size = 0;
    }
    ~Vector()
    {
        delete headNode;
        delete size;
    }


    int Size(){ return *size; } // get the size of a vector
    void Add(var toAdd, int index = 0) // 
    {
        VectorNode<var>* lastNode;
        if (index > (*size))
            index = *size;
        if (index < 1) // add to the end of the vector
        {
            lastNode = tailNode;
        }
        else
        {
            int i;
            if (index <= (*size / 2)) // if the index is less than half the size, iterate forwards
            {
                lastNode = headNode;
                for (i = 1; i <= index; i++){ lastNode = lastNode->Next(); }
            }
            else // otherwise, iterate backwards
            {
                lastNode = tailNode;
                for (i = *size; i >= index; i--){ lastNode = lastNode->Prev(); }
            }
        }
        VectorNode<var>* temp = lastNode->Prev();
        VectorNode<var>* newNode = new VectorNode<var>(toAdd, lastNode, temp);
        lastNode->Prev(newNode);
        temp->Next(newNode);
        *size = *size + 1;
    }
    void Remove(int index) // remove an index
    {
        VectorNode<var>* toRemove;
        VectorNode<var>* lastNode;
        int i;
        if ((index > *size) || (index < 1)) // if not in the domain...
            index = *size;
        if (index <= (*size / 2)) // iterate forwards
        {
            lastNode = headNode;
            for (i = 1; i < index+2; i++){ lastNode = lastNode->Next(); }
        }
        else // iterate backwards
        {
            lastNode = tailNode;
            for (i = *size; i > index; i--){ lastNode = lastNode->Prev(); }
        }
        toRemove = lastNode->Prev();
        VectorNode<var>* temp = toRemove->Prev();
        temp->Next(lastNode);
        lastNode->Prev(temp);
        delete toRemove;
        *size = *size - 1;
    }
    var Index(int index) // get the value of a node
    {
        VectorNode<var>* lastNode;
        int i;
        if (index <= (*size / 2)) // iterate forwards
        {
            lastNode = headNode;
            for (i = 1; i <= index; i++){ lastNode = lastNode->Next(); }
        }
        else // iterate backwards
        {
            lastNode = tailNode;
            for (i = *size; i >= index; i--){ lastNode = lastNode->Prev();}
        }
        return lastNode->Value();
    }

    private:
    int* size;
    VectorNode<var>* tailNode; // the head and tail nodes are placeholders, to keep the list inside its boundaries
    VectorNode<var>* headNode;
};

If you don't feel like reading that, I marked each method with a comment, explaining its overall purpose. Also, I tried adding a small explanation of some of my blocks of code.

And, here's the entry function, and inclusions;

#include "iostream"

#include "stdlib.h" // this has nothing in it that's being used
#include "testhead.h" // the location of the Util namespace

int main()
{
using namespace Util;

Vector<int>* x = new Vector<int>();
x->Add(42);
x->Add(24);
x->Add(12);
x->Add(21);
std::cout << "Listing Indices\n";
for (int i = 1; i <= x->Size(); i++)
{
    std::cout << i << "\t" << x->Index(i) << "\n";
}
std::cout << "Size(pre-removal):\t" << x->Size() << "\n";
x->Remove(2);
std::cout << "Size(post-removal):\t" << x->Size() << "\n";
std::cout << "Listing Indices\n";
std::cout << 3 << "\t" << x->Index(3) << "\n";
for (int i = 1; i <= x->Size(); i++)
{
    std::cout << i << "\t" << x->Index(i) << "\n";
}
system("Pause");

}

Okay, the results I got where this. Before using the Remove method, any index can be accessed from the Vector class freely. But, after using the remove method, no matter what index is removed, no index above one can be accessed. Except, in the case which we remove the first index, then no indices can be accessed. I tried stepping through the code, but it brought me up to this line of code in the index method;

else
{
lastNode = tailNode;
for (i = *size; i >= index; i--){ lastNode = lastNode->Prev();} // error occurs after running this line
}

Now, since I was able to figure out the Remove method was causing the problem, I went back and got some output about that. I had it run the following line prior to finishing its execution, twice. Once before toRemove is deleted, and once again after it is deleted.

std::cout << (lastNode->Prev() == temp) << "\t" << (temp->Next() == lastNode) << "\n";

Before it is removed, it prints 1 twice, indicating the comparison was true. But, the second time I call either the Prev and Next method, and the program freezes. I know this is because I freed the place in memory, but the comparison shows that any references from other nodes to the node I removed were gone. Now, my specific question is why exactly this is being caused, and how can I fix it? I know a little bit about managing memory on the heap, and this doesn't exactly appear as though it would cause any issues with the program. So, I could use a short explanation as to why this happens if anyone would be kind enough to provide it.

If it's any assistance, I'm using the Code::Blocks IDE and the GNU GCC compiler. Also, please tell me if I'm doing something wrong related to the way I asked my quetsion. I don't visit Stack Overflow often, and I don't ask questions here. This is just the best place to have your questions answered that I am aware of.

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

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

发布评论

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

评论(3

楠木可依 2024-10-07 01:06:11

VectorNode 类的析构函数删除 t_next 指针指向的对象指针。在 toRemove 指针上调用 delete 意味着该 VectorNode 对象的析构函数被调用,然后是下一个,然后是下一个,等等。

所以基本上,当您删除 toRemove 时,您会删除 toRemove 以及之后的所有对象这。这会导致 tailNode 的 t_prev 指向您已经释放的内存,然后您尝试在 Index 函数中取消引用这些指针,这不是一件好事。

The destructor of the VectorNode class deletes the object pointer to by the t_next pointer. Calling delete on the toRemove pointer means that the destructor of that VectorNode object gets called, and then the next one, and then the next one etc. etc.

So basically, when you delete toRemove, you delete toRemove and all the objects that come after this. This causes the tailNode's t_prev to point to memory that you have already freed, and you then try dereferencing those pointers in your Index function, and that's not a good thing.

楠木可依 2024-10-07 01:06:11

当您删除其 t_next 成员指向某个其他节点的 VectorNode 时,VectorNode 的析构函数将删除该其他节点(反过来可能会继续删除更多节点)。

当您使用 Remove() 从列表中间删除节点时,该节点的 t_next 将指向列表中的其他节点。当这个节点被删除时,析构函数也会删除链表中跟随它的所有节点。继续使用这个半删除的列表将会导致各种各样的问题。

其他随机观察:

  • 为什么 sizeint* 而不是普通的 intsize_t?我看不出这应该是一个指针的任何理由。
  • new VectorNode(*(new var)) 实际上应该是 new VectorNode(var()) 以避免不必要的内存泄漏。
  • delete 之前的 t_next != NULL 测试是不必要的
  • 您是否计划创建从 VectorNode<> 派生的类?如果不是,那么这些方法就没有理由需要是虚拟的。
  • Add() 中使用从 1 开始的索引是不寻常的,人们会期望从零开始的索引

另外我觉得有义务告诉你,有像 std::liststd::vector 实现了这种结构。

When you delete a VectorNode that has its t_next member pointing to some other node, the destructor of VectorNode will delete that other node (which in turn might go on to delete further nodes).

When you remove a node from the middle of a list with Remove(), the t_next of this node will point to the further nodes of the list. When this node is deleted, the destructor will also delete all the nodes following it in the list. Continuing to use this half-deleted list it will result in all kinds of problems.

Other random observations:

  • Why is size a int* instead of a normal int or size_t? I can't see any reason why this should be a pointer.
  • new VectorNode<var>(*(new var)) should really be new VectorNode<var>(var()) to not unnecessarily leak memory.
  • The t_next != NULL test before delete is unnecessary
  • Are you planning to create classes deriving from VectorNode<>? If not, than there is no reason why the methods would need to be virtual.
  • Using 1-based indexing in Add() is unusual, one would expect zero-based indexing

Also I feel obliged to tell you that there are standard library containers like std::list<> and std::vector<> which implement this kind of structures.

相思碎 2024-10-07 01:06:11

调用remove会删除一个节点,但删除一个节点会删除所有节点->next,

~VectorNode()
{
    if (t_next != NULL)
        delete t_next;
}

因此删除基于1的向量的元素2会杀死您所经历的所有其他元素,并且不再需要调查元素3

Calling remove deletes a node, but deleting a node deletes all the nodes->next

~VectorNode()
{
    if (t_next != NULL)
        delete t_next;
}

so deleting element 2 of your 1 based vector kills all the other elements as you have experienced, and there is no longer an element 3 to investigate

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