Есть ли какое-либо объяснение в стандарте для приведенного ниже поведения?
Следующий код:
#include <sstream>
#include <iostream>
using namespace std;
int main()
{
ostringstream os1;
ostringstream os2;
os1 << 1 << " " << 2;
os2 << 1 << " " << 2 << " " << 3;
const char *p = os1.str().c_str();
cout << os2.str() << endl;
cout << p << endl;
return 0;
}
отображает вывод:
1 2 3
1 2 3
Тем не менее, я ожидаю, что это покажет:
1 2 3
1 2
Похоже, что объект os1 каким-то образом находится под влиянием os2, если я уберу вызов os2.str (), пример будет работать правильно.
Я попробовал пример, если Solaris Studio 12.2 и G ++ 4.8.1 и оба ведут себя одинаково.
Спасибо за вашу помощь!
const char *p = os1.str().c_str();
Вот проблема, в вышеприведенной строке.
os1.str()
возвращает временный строковый объект путем копирования внутреннего строкового буфера. И вы принимаете .c_str()
временного объекта, который уничтожается в конце полного выражения. В результате p
указывает на разрушенный объект, когда вы берете его на печать с помощью std::cout
,
То есть ваша программа вызывает неопределенное поведение (UB).
Попробуй это:
auto s = os1.str();
const char *p = s.c_str(); //s is not a temporary object anymore!
Теперь это дает правильный вывод (а это ваш код — к счастью, даже coliru выдает тот же результат, что и на вашей машине. Обратите внимание, что этот вывод не хотя гарантировано именно потому, что код вызывает UB.)
Я думаю, что проблема связана с сохранением указателя, возвращенного c_str()
,
ostringstream::str()
возвращает временный строковый объект, и вы сохраняете указатель на его внутренний char
массив. Но после выполнения этой строки возвращенный строковый объект будет удален. Таким образом, ваш указатель будет недействительным.
Если по какой-то причине вы хотите сохранить указатель c_str, вам также необходимо сохранить копию строки:
string s = os1.str();
const char *p = s.c_str();
cout << os2.str() << endl;
cout << p << endl;
Ответ на этот вопрос здесь:
путаница преобразования строк, строк и символов *
stringstream.str () возвращает временный строковый объект, который уничтожается в конце полного выражения. Если вы получите указатель на строку C из этого (stringstream.str (). C_str ()), он будет указывать на строку, которая удаляется в том месте, где заканчивается оператор.