Использование QString вызывает сбой после QMap::remove

У меня есть следующий код:

class NamedObjectContainer {
    //...
    QMap<QString, SomeStruct> mUsed;
    //...
};

const StoredObject* NamedObjectContainer::use(const QString& name, const QString& userId)
{
    qDebug()<<userId;
    mUsed.remove(userId);
    qDebug()<<userId;
    //...
}

Здесь я пытаюсь удалить элемент из QMap по ключу (userId). Элемент удаляется правильно. Но, что удивительно, после QMap::remove происходит сбой при печати userId.

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb5b2c6c0 (LWP 24041)]
0xb5fe899c in memcpy () from /lib/i686/nosegneg/libc.so.6
(gdb) where
#0  0xb5fe899c in memcpy () from /lib/i686/nosegneg/libc.so.6
#1  0xb7263246 in QString::append () from /home/osmin/stand_cl_dir/Qt4_x86-linux/lib   /libQtCore.so.4
#2  0xb72b6641 in ?? () from /home/osmin/stand_cl_dir/Qt4_x86-linux/lib/libQtCore.so.4
#3  0xb72b218b in QTextStream::operator<< () from /home/osmin/stand_cl_dir/Qt4_x86-linux/lib/libQtCore.so.4
#4  0xb6524740 in QDebug::operator<< () from /usr/lib/libqxmlrpc.so.1
#5  0xb62b5cc0 in tabexchange::NamedObjectContainer::use (this=0x9e2fb08, name=@0xbffe85e4, userId=@0xa12b780) at namedcontainer.cpp:208

Что может вызвать проблему? Я использую Qt 4.4.3


person Osmin    schedule 19.09.2012    source источник
comment
откуда берется идентификатор пользователя, который вы передаете функции? если прямо из mUsed, то, возможно, он удаляется из карты, а затем вы пытаетесь распечатать ссылку на что-то, что было удалено?   -  person T I    schedule 19.09.2012
comment
Если вы передаете mUsed[что-то]: попробуйте const QString tmp = mUsed[что-то]; ... использовать (имя, временное пространство) ...   -  person Frank Osterfeld    schedule 19.09.2012


Ответы (1)


Чтобы уточнить комментарий @TI...

QString является неявно общим типом. Каждая новая копия объекта QString увеличивает счетчик ссылок, и когда счетчик становится равным нулю, объект уничтожается.

Что, вероятно, произошло здесь, так это то, что была процедура инициализации, которая создала экземпляр QString, передала его в качестве ключа, и карта сделала копию. (Это не копирует данные, а просто увеличивает общий счетчик.) Затем процедура инициализации уничтожила его экземпляр, поэтому остался только тот общий экземпляр, который хранится на карте со счетчиком общих ресурсов, равным 1.

Позже вы, вероятно, использовали что-то вроде QMap::iterator::key(), чтобы получить константная ссылка на ключ строки в карте, переданная как userId. Это не создаст новый экземпляр QString для добавления к общему счету, а скорее укажет на тот, которым владеет карта. Поэтому, когда карта отпускает его... он уничтожается, и теперь userId является оборванной ссылкой.

(Примечание: вы не говорите, что находится в SomeStruct. Но если через него можно было бы получить экземпляр строки, совпадающей с ключом, который будет уничтожен при уничтожении SomeStruct значения карты, то передача ссылки на такой строка userId может вызвать аналогичную проблему.)

Одна вещь, которую добавляет неявное совместное использование, заключается в том, что иногда оно скрывает ошибки такого рода, которые были бы более очевидными без неявного совместного использования. Тем не менее, это делает решение "недорогим": когда вы извлекаете ключ для передачи, копируете его в экземпляр локальной переменной... и передаете константную ссылку на эту переменную в эту процедуру. На самом деле это не приведет к копированию данных, но сделает userId безопасным, потому что будет еще один общий счетчик, поддерживающий его жизнь.

Это помогает реализовать более общий хороший протокол: передача ссылочного типа подпрограмме должна означать, что вы можете гарантировать время жизни ссылочного объекта на все время выполнения вызываемой вами функции. Если есть сомнения, сделайте копию и вместо этого передайте ссылку на копию.

(Примечание. В будущем попробуйте использовать формат Простой, автономный, правильный пример с добавлением и remove включен, это может привести к тому, что вам будет легче найти дымящиеся пушки самостоятельно. А без этого мы можем только делать обоснованные предположения о проблеме... это может быть вызвано чем-то совершенно другим в вашей программе!)

person HostileFork says dont trust SE    schedule 19.09.2012