Будет ли использование c_str во временном режиме по-прежнему завершаться ошибкой при возврате как QString? - PullRequest
0 голосов
/ 16 июня 2020

Я знаю о висячих указателях при неправильном использовании c_str. вот так:

const char* str_ptr = functionReturningString().c_str();
// str_ptr is invalid, as the returned string from the function was temporary, and c_str simply points to that array.

Я хотел бы знать, применимо ли это по-прежнему к этому коду (C ++ 11, Qt 5.5)

 QString UUId::toString () const
 {
    return to_string (_uuid).c_str();
 }

Здесь используется функция to_string из класса boost s uuid.

возвращает std::string. Это временный объект, и я ожидаю, что c_str() будет опасным.

Тип возвращаемого значения QString как-то меняет это? Я не уверен, что это на самом деле означает:

return QString(to_string (_uuid).c_str()); (я просто предполагаю)

, который должен создать копию (если вы посмотрите на QString (const char * ) конструктор) если не ошибаюсь.

Вопрос : Это безопасно? Или темп разрушается до того, как будет построен QString?

Ответы [ 2 ]

1 голос
/ 17 июня 2020

Уменьшенная версия вашего кода:

QString toString(const boost::uuids::uuid &uuid)
{
  return to_string(uuid).c_str();
}

Это безопасно, потому что вы используете c_str() только для инициализации содержимого QString. QString обрабатывает строку C как UTF-8 и инициализирует внутреннее хранилище UTF-16 путем перекодирования из UTF-8 в UTF-16. Это, конечно, копирует все данные, поэтому к тому времени, когда полное возвращаемое выражение завершит вычисление, создается QString. Только тогда std::string, к которому вы обращаетесь через c_str(), уничтожается.

То, что здесь делает return, действительно выглядит следующим образом:

QString toString(const boost::uuids::uuid &uuid)
{
  return QString(to_string(uuid).c_str());
}

Опять же: деструкторы запускаются после того, как было вычислено полное выражение, полное выражение - это вызов QString конструктора. Итак, временный std::string должен быть живым до тех пор, пока QString не закончит построение.

И эта QString конструкция всегда копия. Независимо от того, откуда взялась строка C, она будет скопирована во время транскодирования в UTF-16. Другими словами: копия не идентична битам, но идентична кодовой точке Unicode. Это приводит к представлению UTF-16 точек кода Unicode, которые были представлены кодировкой UTF-8 в строке C. Кодовые точки можно представить в некотором упрощении как 32-битные целые числа.

1 голос
/ 17 июня 2020

Чтобы ответить на вопрос

Это безопасно? Или темп уничтожается до того, как будет построен QString?

QString UUId::toString () const
 {
    return to_string (_uuid).c_str();
 }

Это безопасно .

Как уже упоминалось в OP, результат std::string::c_str() действителен только до тех пор, пока соответствующий std::string не изменен (включая не удаленный).

Функция должна возвращать QString, а return вызывается с const char* . Компилятор примет его, если найдет преобразование из const char* в QString. При определенных условиях это будет:

Qstring :: QString (const char * str)

Создает строку, инициализированную с помощью 8 -битовая строка str. Указанный указатель const char преобразуется в Unicode с помощью функции fromUtf8 ().

Вы можете отключить этот конструктор, определив QT_NO_CAST_FROM_ASCII при компиляции ваших приложений. Это может быть полезно, если вы хотите убедиться, что все видимые пользователю строки go через QObject :: tr (), например.

Итак, вопрос сводится к:

Имеет ли std::string, возвращенный из to_string(), достаточно долго, чтобы передать конструктору QString указатель на его внутреннюю необработанную строку?

Да.

Из cppreference - Время жизни временного объекта :

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

Полное выражение в данном случае to_string (_uuid).c_str() (т.е. все после return и до ;).


Чтобы сделать это немного более явным и надежным (например, независимо от того, определено ли QT_NO_CAST_FROM_ASCII или нет), я бы написал его как:

QString UUId::toString() const
{
  return QString::fromUtf8(to_string(_uuid).c_str());
}

но

QString UUId::toString() const
{
  return QString::fromStdString(to_string(_uuid));
}

должно быть довольно эквивалентным, потому что это также предполагает закодированное в UTF-8 содержимое переданного аргумента. ( QString :: fromStdString () )

...