Qt QList не добавляет локальные объекты

У меня проблема с пониманием, почему следующий код не сохраняет какие-либо объекты QString в моем 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();

Выход: 0


person blackworker    schedule 23.12.2014    source источник
comment
Вы слышали о QStringList?   -  person lpapp    schedule 23.12.2014
comment
Да, я использовал в этом примере QString-Objects, чтобы продемонстрировать свою проблему. В реальном приложении я использую дополнительный класс без наследования QObject. Это моя вина, может быть, я должен уточнить это в вступительном посте...   -  person blackworker    schedule 23.12.2014
comment
Ни QString, ни QList не наследуют QObject.   -  person lpapp    schedule 23.12.2014
comment
Хорошо, lpapp, тогда мой пример проблемы представляет мою реальную проблему без каких-либо модификаций.   -  person blackworker    schedule 23.12.2014
comment
@IrfanDANISH: пожалуйста, не удаляйте намеренно добавленные теги, спасибо.   -  person lpapp    schedule 25.12.2014


Ответы (2)


Причина проста: копировать при записи, т.е. неявный общий доступ

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

На данный момент у вас еще нет печатной копии, только «ссылка». Это несправедливо в стандартном смысле С++, но представьте себе это как «поверхностную копию». Однако, когда вы начнете добавлять сюда, список будет скопирован, а оригинал останется пустым. Это связано с тем, что QList реализован так же, как CoW (копирование при записи). ).

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

Кстати, вы можете взглянуть на QStringList. Хотя он наследует QList, он также имеет несколько дополнительных удобных методов.

Теперь вы можете спросить: How am I supposed to fill my map in, then?.

Мульти карта

Лично я бы посоветовал использовать QMultiMap или хотя бы QMap с 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

Построить и запустить

qmake && make && ./main

Выход

2

Единая карта

Если вы придерживаетесь текущего подхода, я бы предложил либо добавить значение в новый QStringList, которым вы перезапишете значение, либо сохранить ссылку на тот же самый список.

Сказав это, в вашем случае кажется излишним даже рассматривать возможность вставки внешнего хранилища. По моему скромному мнению, вы должны сделать это немедленно.

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

Построить и запустить

qmake && make && ./main

Выход

2
person lpapp    schedule 23.12.2014
comment
Спасибо за ваши усилия. Я буду исследовать неявное совместное использование — я думаю, что это содержит ключевые факты, которые мне нужны для более широкой картины о Qt. В настоящее время у меня есть небольшое представление о том, что может существовать только один реальный экземпляр перечисленных классов qt: doc-snapshot.qt-project.org/qt5-5.4/implicit-sharing.html Поэтому я не могу иметь несколько указателей на один уникальный экземпляр для доступа/изменения его. Единственное, чего я не понимаю, так это почему это работает с использованием ссылок. Но я думаю, что в течение следующего часа все прояснится для меня :) Большое спасибо за вашу помощь lpapp! - person blackworker; 23.12.2014
comment
@blackworker: потому что в этом случае вы не создаете поверхностную копию. У вас есть только ссылка. На самом деле, неважно, CoW это или value copy, нужна только справка для таких случаев. Но опять же, я думаю, что вы не должны использовать внешнюю переменную для таких простых случаев в первую очередь. Посмотрите мои 3-4 строки выше, насколько это проще, чем ваш исходный беспорядочный код. :) - person lpapp; 23.12.2014
comment
@lpapp Все верно, но в данном случае я думаю проблема не в этом. Решение такое, которое описал Андрей. - person p.i.g.; 29.05.2015

Согласно документации ваш образец должен быть изменен следующим образом :

QMap<QString, QList<QString> >map;
QList<QString> & listInMap = map["eins"]; // use reference here
listInMap.append("test1");
listInMap.append("test2");
QList<QString> copyOfListInMap = map.value("eins");
qDebug() << copyOfListInMap.count();
person Andrii    schedule 23.12.2014
comment
Это решает актуальную мою проблему, спасибо Андрей! Но я не понимаю, почему это не сработает, если я использую указатель, а не ссылку. Кроме того, у меня также нет предупреждения компилятора об этом? - person blackworker; 23.12.2014
comment
@blackworker: из-за CoW, как описал lpapp в своем ответе - person Andrii; 23.12.2014