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

时间:2010-10-29 22:37:05

标签: c++ runtime freeze codeblocks

我编写了一个简单的控制台程序,用于测试我正在构建的库中的一些关键类。现在,代码构建正确,没有错误。但是,在执行代码之后,我发现应用程序在代码中的某个点调用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() { 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");

}

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

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方法,我回过头来得到一些关于它的输出。我让它在完成执行之前运行以下行,两次。删除前删除一次,删除后再删除。

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

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

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

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

当您删除VectorNode成员指向某个其他节点的t_next时,VectorNode的析构函数将删除该另一个节点(进而可能继续删除该节点)节点)。

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

其他随机观察:

  • 为什么sizeint*而非普通intsize_t?我看不出为什么这应该是一个指针。
  • new VectorNode<var>(*(new var))应该是new VectorNode<var>(var()),以免不必要地泄漏内存。
  • t_next != NULL之前的delete测试是不必要的
  • 您是否计划创建源自VectorNode<>的类?如果没有,则没有理由认为这些方法需要virtual
  • Add()中使用基于1的索引是不寻常的,可以预期基于零的索引

此外,我觉得有必要告诉您,有std::list<>std::vector<>等标准库容器可以实现这种结构。

答案 2 :(得分:1)

调用删除删除节点,但删除节点会删除所有节点 - >下一步

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

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