QList、QLinkedList和std::list
可能切换到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.