2010-10-01 74 views
1

我用wxWidgets編寫了一個應用程序,它使用wxList。我在收集列表數據的析構函數中有一些隨機crahses(segfault)。我找不到從列表中刪除項目的明確方法(Erase()VS DeleteNode())。即使迭代項目有兩種風格(list-> GetFirst()VS list-> begin())。在wxWidgets中處理鏈表的正確方法是什麼?

下面是一個測試類,顯示我在我的應用程序中使用的方法。測試運行完美,沒有崩潰。似乎有些指針在被釋放後正在使用,但我無法通過查看代碼來判斷。我想我在做Erase()和DeleteContents()調用時會出錯。

P.S:在應用程序中,列表包含大約15000個項目,而測試中僅包含9個項目。

#include <wx/list.h> 
#include <wx/log.h> 

class TestItem 
{ 
public: 
    TestItem(int _x, int _y) { x = _x; y = _y; } 
    int x; 
    int y; 
}; 

WX_DECLARE_LIST(TestItem, TestList); 

#include <wx/listimpl.cpp> 
WX_DEFINE_LIST(TestList); 

class Test { 

public: 
    TestList *list; 
    Test() { 
     list = new TestList; 
    } 

    ~Test() { 
     Clean(); 
     delete list; 
    } 


    void CreateAndAddToList(int x, int y) { 
     TestItem *item = new TestItem(x, y); 
     list->Append(item); 
    } 

    void PrintAll() { 
     wxLogMessage(wxT("List size: %d"), list->GetCount()); 
     wxTestListNode *node = list->GetFirst(); 
     while (node) { 
      TestItem *item = node->GetData(); 
      wxLogMessage(wxT("Item: %d, %d"), item->x, item->y); 
      node = node->GetNext(); 
     } 
    } 

    void DeleteAllX(int x) { 
     wxTestListNode *node = list->GetFirst(); 
     while (node) { 
      TestItem *item = node->GetData(); 
      if (item->x != x) { 
       node = node->GetNext(); 
       continue; 
      } 
      wxTestListNode *toDelete = node; 
      node = node->GetNext(); 
      wxLogMessage(wxT("Deleting item: %d, %d"), item->x, item->y); 
      list->Erase(toDelete); 
      delete item; 
     } 
    } 

    void Clean() { 
     list->DeleteContents(true); 
     list->Clear(); 
    } 

    static void DoAllTests() { 
     Test *t = new Test; 
     t->CreateAndAddToList(1, 1); 
     t->CreateAndAddToList(1, 2); 
     t->CreateAndAddToList(1, 3); 
     t->CreateAndAddToList(2, 1); 
     t->CreateAndAddToList(2, 2); 
     t->CreateAndAddToList(2, 3); 
     t->CreateAndAddToList(3, 1); 
     t->CreateAndAddToList(3, 2); 
     t->CreateAndAddToList(3, 3); 
     t->PrintAll(); 
     t->DeleteAllX(2); 
     t->PrintAll(); 
     t->Clean(); 
     t->PrintAll(); 
     delete t; 
    } 
}; 
+1

你可以避免頭痛和麻煩,並使用'std :: list'。已經由數百萬用戶進行編碼和測試。 – 2010-10-01 21:16:44

+0

我沒有注意到wxList已被棄用的文檔。無論如何,新的API幾乎與std :: list相同。我改變了我的應用程序使用std :: list,一些錯誤似乎消失了。至少現在我有更多關於列表後端的文檔。 – streeto 2010-10-06 13:45:36

回答

0

論wxList API list->GetFirst()list->begin()之間的區別,這似乎是list->GetFirst(),則返回null列表是空的,list->begin()像往常一樣爲其他迭代器返回迭代器的值以結束list->end()list->GetFirst()是舊的API,list->begin()是新的。主要的好處是可以讓你使用期望帶有wxList的迭代器的模板。

wxList被認爲已被棄用,並被std :: list取代,但不應該擔心你太多,因爲它是在內部使用新版本的wx(wxList只是成爲wxList的一個薄包裝)。

無論如何,你使用它的方式似乎很好,即使它可以稍微簡化,我在DeleteAllX()中也看不到明顯的錯誤。

我會懷疑的是,一些以前的內存分配失敗(如果它是通過malloc完成的話,可能會非常沉默),並在以後刪除時在列表中造成嚴重破壞,或者segfault發生在析構函數當你調用delete時你自己的對象。由於許多編程錯誤可能導致這種情況,它比wxList中的一些問題更容易發生,包括分配問題。然而,這很容易檢查,只需跟蹤你的析構函數的調用,並且如果segfaults從那裏來的話就足夠快了。

0

我從來沒有使用wxWidgets的,但我認爲,如果你傳遞這樣一個參數,它是不是在名單DeleteAllX將失敗。它會在以下行失敗:

node = node->GetNext(); 

請確保這不會發生在原來的應用程序。你從指針得到的東西之前,你也可以把斷言爲指針訪問:

TestItem *item = node->GetData(); 
assert(item); 
if (item->x != x) { 
    node = node->GetNext(); 
    assert(node); 
    continue; 
} 

相關問題