Edited at

QList のイテレータ無効化の罠


事の起こり

std::listは元のコンテナに新たな要素の挿入がされてもイテレータは無効にならない

QtのコンテナはSTLのコンテナに似せて作ってあるのだからQListも同様だろう

そう思っていた時期が私にもありました

そしてQtがよく使っているデータ型はQStringList QVariantList QTestEventList...と非常によくQListを使用してくるのでそれに合わせて自コードをstd::listからQListに置き換えているときに事故は起こった


Qtのコンテナって癖あるよね

QList::iterator


However, be aware that any non-const function call performed on the QList will render all existing iterators undefined. If you need to keep iterators over a long period of time, we recommend that you use QLinkedList rather than QList.


なんと(?)QListでは要素の挿入でイテレータが無効になるようです。

なんとQLinkedListとかいう尤もな名前のコンテナがありました。というかQListはリンクリストではありませんでした

(命名の重要性!)

(まあよく考えれば添え字アクセスできる時点で気付いても良かったのかも)


検証コード

Qt5.13.1 msvc2017 で検証

#include <iostream>

#include <QList>
#include <QLinkedList>
#include <QDebug>

int main()
{
std::cout << std::boolalpha;

std::list<int> a;
// QList<int> a;
// QLinkedList<int> a;

a.push_back(1);

auto b = a.begin();
auto e = a.end();

a.push_back(2);
a.push_back(3);

qDebug() << (b == a.begin()) << (e == a.end());

return 0;
}


結果

begin
end

std::list
true
true

QList
false
false

QLinkedList
true
true

はい