Search code examples
c++qtqtcoreqlistqmap

Qt QList does not append local Objects


I have a understanding-problem why following code does not store any QString-Objects into my QList

QMap<QString, QList<QString> >map;
map = QMap<QString, QList<QString> >();
map.insert("eins", QList<QString>());
QList<QString> listInMap = map["eins"];
listInMap.append("test1");
listInMap.append("test2");
QList<QString> copyOfListInMap = map.value("eins");
qDebug() << copyOfListInMap.count();

Output: 0


Solution

  • The reason is simple: copy on write, aka. implicit sharing

    QList<QString> listInMap = map["eins"];
    

    At this point, you have not yet got a hard copy, only a "reference". That is not fair in the standard C++ sense, but imagine it as a "shallow copy". However, when you start appending in here, the list will copied and the original will left empty. It is because QList is implemented the way that is CoW (copy-on-write).

    listInMap.append("test1");
    listInMap.append("test2");
    

    On a side note, you may wish to take a look at QStringList. While it inherits QList, it also has some additional convenience methods.

    Now, you may be asking: How am I supposed to fill my map in, then?.

    Multi map

    I would personally suggest to use QMultiMap or at least QMap with insertMulti.

    main.cpp

    #include <QMap>
    #include <QDebug>
    #include <QString>
    
    int main()
    {
        QMultiMap<QString, QString> map;
        map.insert("eins", "test1");
        map.insert("eins", "test2");
        qDebug() << map.count();
        return 0;
    }
    

    main.pro

    TEMPLATE = app
    TARGET = main
    QT = core
    SOURCES += main.cpp
    

    Build and Run

    qmake && make && ./main
    

    Output

    2
    

    Single map

    If you stick to the current approach, I would suggest to either append the value into a new QStringList with which you will overwrite the value, or hold a reference to the exact same list.

    Having said that, in your case, it looks a bit overkill to even consider an external storage for insertion. You ought to do that right away in my humble opinion.

    main.cpp

    #include <QMap>
    #include <QDebug>
    #include <QString>
    
    int main()
    {
        QMap<QString, QStringList> map;
        map.insert("eins", QStringList{"test1", "test2"});
        qDebug() << map.value("eins").count();
        return 0;
    }
    

    main.pro

    TEMPLATE = app
    TARGET = main
    QT = core
    CONFIG += c++11
    SOURCES += main.cpp
    

    Build and Run

    qmake && make && ./main
    

    Output

    2