2010-10-29 86 views
1

我編寫了一個簡單的控制檯程序,用於測試我正在構建的庫中的一些關鍵類。現在,代碼正確構建,沒有錯誤。但是,在執行代碼之後,我發現應用程序在代碼中的某個點調用Index方法後停止工作。我試着調試幾種不同的方式來獲得更多關於這個問題的信息,但是我收集的信息根本沒有幫助我。也許它會幫助別人知道我沒做什麼(或做錯了)。C++可執行文件在運行時凍結

下面是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方法之後,無論索引被刪除,都不能訪問超過一個的索引。除了我們刪除第一個索引的情況外,沒有索引可以被訪問。我嘗試了一下代碼,但是它讓我在索引方法中找到了這行代碼;

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

現在,由於我能夠找出Remove方法導致的問題,我回去並得到了一些輸出。在完成執行之前,我已經執行了兩行。刪除之前一次刪除,刪除後再次刪除。

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

在刪除它之前,它會打印兩次,表示比較結果爲真。但是,第二次調用Prev和Next方法時,程序凍結。我知道這是因爲我釋放了內存中的位置,但比較顯示從其他節點到我刪除的節點的任何引用都消失了。現在,我的具體問題是爲什麼這會導致這種情況,我該如何解決這個問題?我知道一些關於在堆上管理內存的問題,而這並不像看起來會導致程序出現任何問題。所以,我可以用一個簡短的解釋來解釋爲什麼會有這種情況發生,如果有人願意提供它。

如果有任何幫助,我使用Code :: Blocks IDE和GNU GCC編譯器。另外,請告訴我,如果我做錯了有關我問我的quatsion的方式。我不經常訪問Stack Overflow,我在這裏不提問題。這是我知道的回答問題的最佳地點。

+0

您是否嘗試使用調試器進行調試?或添加跟蹤語句? – 2010-10-29 22:40:56

+0

人們將會看到Vector並做出它是標準的假設。 – 2010-10-29 22:54:03

回答

2

VectorNode類的析構函數通過t_next指針刪除對象指針。調用toRemove指針的delete意味着該VectorNode對象的析構函數被調用,然後是下一個,然後是下一個等等。

所以基本上,當刪除toRemove時,刪除toRemove和所有在此之後出現的對象。這會導致tailNode的t_prev指向已經釋放的內存,然後嘗試解除索引函數中的這些指針的引用,這不是一件好事。

1

當您刪除的t_next成員指向某個其他節點時,VectorNode的析構函數將刪除該另一個節點(進而可能會繼續刪除其他節點)。

Remove()列表的中間刪除節點時,此節點的t_next將指向列表的其他節點。當這個節點被刪除時,析構函數也將刪除列表中的所有節點。繼續使用這個半刪除的列表會導致各種問題。

其他隨機觀察:

  • 爲什麼size一個int*,而不是一個正常的intsize_t?我不明白爲什麼這應該是一個指針。
  • new VectorNode<var>(*(new var))應該真的是new VectorNode<var>(var())不會不必要地泄漏內存。
  • t_next != NULL測試delete之前是不必要的
  • 你打算創建VectorNode<>派生類?如果沒有,比沒有理由爲什麼方法將需要是virtual
  • 使用基於1的索引中Add()是不尋常的,人們所期望的從零開始的索引

此外,我覺得有必要告訴你,有標準庫容器,如std::list<>std::vector<>它們實現這種結構。

1

調用remove刪除一個節點,但刪除節點刪除所有的節點 - >未來

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

所以刪除您的1個基於矢量的元素2殺死你所經歷過的所有其他元素,且有不再是要調查的元素3