在wxWidgets中处理链表的正确方法是什么?

时间:2010-10-01 20:46:58

标签: c++ linked-list wxwidgets

我使用使用wxList的wxWidgets编写了一个应用程序。我在收集列表数据的析构函数中有一些随机的crahses(segfault)。我找不到从列表中删除项目的明确方法(Erase()VS DeleteNode())。即使遍历项目也有两种风格(list-> GetFirst()VS list-> begin())。

下面是一个测试类,显示了我在我的应用程序中使用的方法。测试运行完美,没有崩溃。似乎有些指针在被释放后被使用,但我无法通过查看代码来判断它。我想在Erase()和DeleteContents()调用周围做错了。

P.S:在应用程序中,该列表包含大约15,000个项目,而不是测试中的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;
    }
};

2 个答案:

答案 0 :(得分:0)

我从未使用wxWidgets,但我认为DeleteAllX如果传递了不在列表中的参数,则会失败。它将在以下行中失败:

node = node->GetNext();

确保在原始应用中不会发生这种情况。您还可以在从指针获取内容之前将断言置于指针访问中:

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

答案 1 :(得分:0)

关于wxList API中list->GetFirst()list->begin()之间的区别,如果list为空并且list->GetFirst()返回迭代器的值,则list->begin()返回NULL似乎是像往常一样结束list->end()其他迭代器。 list->GetFirst()是旧API,list->begin()是新API。主要的好处是允许您使用期望带有wxList的迭代器的模板。

wxList被认为已被弃用并被std :: list取代,但是这不应该让你太担心,因为它是在新版本的wx内部完成的(wxList只是wxList上的一个瘦包装器)。

你使用它的方式似乎很好,我发现DeleteAllX()中没有明显的错误,即使它可以略微简化。

我怀疑的是,之前的某些内存分配失败(如果通过malloc完成,可能会非常安静)并在以后删除时导致列表中出现严重破坏,或者在您的析构函数内部发生了段错误调用delete时自己的对象。由于许多编程错误可能导致这种情况,因此它看起来比wxList的某些问题更容易发生,包括分配问题。然而,这很容易检查,只是跟踪你的析构函数的调用,如果来自那里的段错误,你很快就会知道。