Сбой в QString toUtf8()

У меня есть слот:

void Foo::func(QString str1, const QString& str2, int width, int height)
{
    std::unique_lock<std::mutex> _lock(m_mutex);

#ifdef _DEBUG
    MEMORYSTATUSEX statex;
    statex.dwLength = sizeof (statex);
    if (GlobalMemoryStatusEx(&statex)) {
        qDebug() << QString("There are %1 free MB of physical memory.\n").arg(statex.ullAvailPhys / 1024 / 1024);
    }
#endif

    BaseClass::someFunc(
        str1.toStdString(),
        str2.toUtf8().constData(),
        width,
        height
    );
}

Вроде правильно и работает. Но если программа работает долго (ночью например) она вылетает в этой функции на строке

str2.toUtf8().constData()

Сначала я подумал, что это ошибка на основе потока, но моя блокировка не сработала. Все локальные переменные и члены класса в порядке. Ошибка сбоя:

First-chance exception at 0x76E45B68 foo.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x00EFC6EC

Но из приведенного выше кода последний MEMORYSTATUSEX показывает, что доступная память

There are 2314 free MB of physical memory

Я также подумал, что str2 слишком большой, но он отлично работает с длиной 49152, 168441 и т. д. В чем проблема? Я что-то пропустил?

Трассировки стека:

    KernelBase.dll!_RaiseException@16()    Unknown
[External Code] 
Qt5Cored.dll!qBadAlloc() Line 2849  C++
Qt5Cored.dll!QByteArray::QByteArray(int size, Qt::Initialization __formal) Line 1409    C++
Qt5Cored.dll!QUtf8::convertFromUnicode(const QChar * uc, int len) Line 151  C++
Qt5Cored.dll!QString::toUtf8_helper(const QString & str) Line 4373  C++
Qt5Cored.dll!QString::toUtf8() Line 56  C++
foo.exe!Foo::func(QString str1, const QString & str2, int width, int height) Line 3600  C++
foo.exe!Foo::qt_static_metacall(QObject * _o, QMetaObject::Call _c, int _id, void * * _a) Line 1126 C++
Qt5Cored.dll!QMetaObject::activate(QObject * sender, int signalOffset, int local_signal_index, void * * argv) Line 3717 C++
Qt5Cored.dll!QMetaObject::activate(QObject * sender, const QMetaObject * m, int local_signal_index, void * * argv) Line 3582    C++
foo.exe!SomeClass::func(QString _t1, const QString & _t2, int _t3, int _t4) Line 137    C++
foo.exe!SomeClass::qt_static_metacall(QObject * _o, QMetaObject::Call _c, int _id, void * * _a) Line 81 C++
Qt5Cored.dll!QMetaCallEvent::placeMetaCall(QObject * object) Line 485   C++
Qt5Cored.dll!QObject::event(QEvent * e) Line 1246   C++
Qt5Widgetsd.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3720    C++
Qt5Widgetsd.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3164  C++
Qt5Cored.dll!QCoreApplication::notifyInternal(QObject * receiver, QEvent * event) Line 935  C++
Qt5Cored.dll!QCoreApplication::sendEvent(QObject * receiver, QEvent * event) Line 228   C++
Qt5Cored.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1552    C++
Qt5Cored.dll!QCoreApplication::sendPostedEvents(QObject * receiver, int event_type) Line 1410   C++
qwindowsd.dll!QWindowsGuiEventDispatcher::sendPostedEvents() Line 81    C++
Qt5Cored.dll!qt_internal_proc(HWND__ * hwnd, unsigned int message, unsigned int wp, long lp) Line 414   C++
[External Code] 
Qt5Cored.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 807    C++
qwindowsd.dll!QWindowsGuiEventDispatcher::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 73   C++
Qt5Cored.dll!QEventLoop::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 129   C++
Qt5Cored.dll!QEventLoop::exec(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 204    C++
Qt5Cored.dll!QCoreApplication::exec() Line 1188 C++
Qt5Guid.dll!QGuiApplication::exec() Line 1508   C++
Qt5Widgetsd.dll!QApplication::exec() Line 2957  C++
foo.exe!WinMain(HINSTANCE__ * __formal, HINSTANCE__ * __formal, char * lpCmdLine, int __formal) Line 348    C++
[External Code] 

Заранее спасибо!


person user2123079    schedule 01.06.2016    source источник
comment
Может проблема в фрагментации памяти? Всего у вас может быть 2314 free MB, но, например, фрагменты памяти длиной ‹ 1 КБ, тогда вы не можете использовать 40 КБ для строки.   -  person fghj    schedule 01.06.2016
comment
Кстати, использование таких конструкций, как str2.toUtf8().constData(), очень плохая практика, потому что вы возвращаете указатель на внутренности временных объектов. Таким образом, str2.toUtf8().constData() будет недействительным сразу после вызова BaseClass::someFunc. Так что если вы его где-то передадите, у вас будут проблемы   -  person Dmitry Sazonov    schedule 01.06.2016
comment
Что ж, я проверю момент фрагментации памяти и напишу результат здесь позже.   -  person user2123079    schedule 01.06.2016
comment
Что произойдет, если вы сделаете str2 простой QString вместо константной ссылки? Может ли быть так, что строка, переданная как str2, одновременно изменяется где-то еще?   -  person Silicomancer    schedule 02.06.2016
comment
Я думал об этом и уже пытался, но если я это сделаю, поведение будет таким же. (просто забыл об этом написать)   -  person user2123079    schedule 02.06.2016
comment
Об этой проблеме, возможно, сообщили около полувека назад, но она все еще поднимает свою уродливую голову. Кто-нибудь знает потенциальные причины этого сбоя?   -  person RAM    schedule 03.03.2021


Ответы (1)


Для тех, кто, как и я, просто наткнулся на эту ветку, потому что хотел преобразовать QString в char * с вызовом str.toUtf8().constData() или str.toUtf8().data(), но это приводило к сбою программы или выдаче исключения, такого как EXC_BAD_ACCESS в XCode, вот отвечать:

  • в таком вызове, как foo = str.toUtf8().constData();, часть str.toUtf8() создает временный объект.
  • вызов tmp.data() или tmp.constData() возвращает указатель на внутренний буфер, управляемый самим объектом, время жизни которого привязано к времени жизни временного объекта. источник.
  • как только этот оператор будет выполнен, время жизни объекта, адрес которого был назначен foo, когда-то возвращенный data() или constData(), закончится.
  • поэтому, как и ожидалось, после этого оператора foo будет храниться адрес объекта, время жизни которого закончилось, что приведет к сбоям и исключениям.
person RAM    schedule 02.03.2021