У меня есть следующий код:
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). Элемент удален правильно. Но неожиданно происходит сбой при печати userId после QMap :: remove.
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
Чтобы уточнить комментарий @ TI …
QString является неявно разделяемый тип. Каждая новая копия, сделанная из объекта QString, увеличивает счетчик ссылок под капотом, а когда счетчик становится равным нулю, он уничтожается.
Вероятно, здесь произошло то, что существовала подпрограмма инициализации, которая создала экземпляр QString, передала его в качестве ключа, и карта сделала копию. (Это не копирует данные, а просто увеличивает общее количество.) Затем процедура инициализации уничтожила свой экземпляр, так что единственный оставшийся общий экземпляр — это тот, который хранится на карте с количеством ресурсов 1.
Позже вы, вероятно, использовали что-то вроде QMap::iterator::key()
чтобы получить постоянную ссылку на строковый ключ на карте, переданный как userId
, Это не создало бы новый экземпляр QString для добавления к общему количеству, а скорее указало бы на тот, который принадлежит карте. Итак, когда карта отпускает это … она разрушена и теперь userId
это свисающая ссылка.
(Примечание: вы не говорите, что в SomeStruct
, Но если через него может быть получен экземпляр совпадающей строки с ключом, который будет уничтожен, когда значение карты SomeStruct
уничтожается, а затем передает ссылку на такую строку, как userId
может вызвать аналогичную проблему.)
Одна вещь, которую неявное совместное использование бросает в смесь, состоит в том, что иногда это скрывает ошибки такого рода — что было бы сделано более очевидным без неявного совместного использования. Тем не менее это делает решение «недорогим»: когда вы извлекаете ключ для передачи, копируете его в экземпляр локальной переменной … и передаете постоянную ссылку на тот переменная к этой рутине. Это на самом деле не будет копировать данные, но это сделает userId
безопасно, потому что будет еще один общий счет, сохраняющий его.
Это помогает реализовать более общий хороший протокол: передача ссылочного типа в процедуру должен означает, что вы можете гарантировать время жизни ссылочного объекта в течение всего времени выполнения функции, которую вы вызываете. Если это вызывает сомнения, сделайте копию и передайте ссылку на копию.
(Примечание: в будущем попробуйте использовать Простой, самостоятельный, правильный пример форматирование с добавлением и удалением, это может привести к более легкому поиску курящих пистолетов. А без этого мы можем только догадываться о проблеме … это может быть вызвано чем-то другим в вашей программе целиком!)
Других решений пока нет …