Проблема с передачей указателя на строку ostringstream
По совету ChatGPT писал код для работы с cURL, в котором был фрагмент
std::ostringstream postFields;
// Долгая запись в postFields...
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields.str().c_str());
Все это не работало - тело запроса никак не передавалось. Как будто его нет. Путем проб и ошибок нашел, что проблема во второй строке.
Стоило сделать так:
std::string g = postFields.str();
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, g.c_str());
или даже
const std::string& g = postFields.str();
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, g.c_str());
как все отлично работало.
У меня подозрения, что это связано с какими-то тонкостями передачи - получить строку, а потом из нее указатель, и что-то по дороге портится, вроде как с возвратом локальной переменной из функции.
Поэтому вопрос - я прав ли нет? Если нет, то в чем тогда дело - почему начальный код не работает, если прав - то расскажите подробнее. И как вообще находить такие странны места в языке.
Ответы (1 шт):
Начинаем с очевидных вещей:
std::ostringstream::str()
возвращает строку по значению, эта строка умирает в конце текущего выражения (грубо говоря, на ближайшем ;
, т.е. в конце текущей строки кода).
Это было бы нормально, если бы curl_easy_setopt
делал себе копию строки, но судя по всему, он ее не делает, и расчитывает на то, что строка продолжит существовать.
И действительно, если открыть мануал:
Strings passed to libcurl as
char *
arguments, are copied by the library; the string storage associated to the pointer argument may be discarded or reused aftercurl_easy_setopt
returns. The only exception to this rule is reallyCURLOPT_POSTFIELDS
, but the alternative that copies the stringCURLOPT_COPYPOSTFIELDS
has some usage characteristics you need to read up on.
Т.е. если не хочется хранить строку самому, то нужно использовать CURLOPT_COPYPOSTFIELDS
.
Ну и мелочь: Такой вызов .str()
создает лишнюю копию строки. Правильнее так: std::move(postFields).str()
.