QList、QLinkedList和std::list

July 29, 2008 at 4:08 pm (nlp)

可能切换到QT开发环境下的人都会遇到过这个问题。QT提供了一套类似STL的容器供
开发人员使用。多数情况下用法是尊重STL用户的习惯的,然而在当遇到性能和迭代器的有效性的时候,就要注意一些细小的差异了。如果忽视这些差异,不仅无法写出高效的程序,还会使程序遇到意想不到的问题。 比如QList,直觉就会觉得它是一个链表,可以他的存储方式却和std::list非常的不一样:

struct Q_CORE_EXPORT QListData {
    struct Data {
        QBasicAtomic ref;
        int alloc, begin, end;
        uint sharable : 1;
        void *array[1];
    };
    。。。
    Data *d;
    。。。
    inline int size() const { return d->end - d->begin; }
    inline bool isEmpty() const { return d->end  == d->begin; }
    inline void **at(int i) const { return d->array + d->begin + i; }
    inline void **begin() const { return d->array + d->begin; }
    inline void **end() const { return d->array + d->end; }
};

可以看出其访问指针的存储是由一段连续的内存空间组成的,而不同元素之间的空间却不连续。这样保证了类似std::vector的下标访问,又不至于像Vector那样在元素增多时随机插入的性能下降得太多。但是QList依然无法获得稳定的插入和删除复杂度,也无法保证迭代器在插入和删除后的有效性。 而QLinkedList,则是一个和std::list类似的双向链表。从其实现可以看出:

template <typename T>
 struct QLinkedListNode {
 inline QLinkedListNode(const T &arg)
: t(arg) 
{ }
 QLinkedListNode *n, *p; T t;
 };

其结构保存了前后相邻元素的指针。这样既可以获得稳定的元素随机插入性能,由可以保证在增删元素之后已赋值的迭代器依然有效。因此,STL的程序员应当使用QLinkedList来替代std::list.而对于没有连续内存操作,只希望下标随机访问的应当使用QList.

Permalink Leave a Comment

Follow

Get every new post delivered to your Inbox.