2010-10-01 98 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; 
} 

相关问题