2010-04-17 6 views
8

Это из небольшой библиотеки, которую я нашел на сайте:Возвращение «c_str» из функции

const char* GetHandStateBrief(const PostFlopState* state) 
{ 
    static std::ostringstream out; 

    // ... rest of the function ... 

    return out.str().c_str() 
} 

В моем коде я это делаю:

const char *d = GetHandStateBrief(&post); 
std::cout<< d << std::endl; 

Теперь на первый d содержала мусора , Затем я понял, что строка C, которую я получаю от функции, уничтожается, когда функция возвращается, потому что в стеке выделено std::ostringstream. Поэтому я добавил:

return strdup(out.str().c_str()); 

И теперь я могу получить текст, который мне нужен от функции.

У меня есть два вопроса:

  1. Могу ли я понимающих это правильно?

  2. Я позже заметил, что out (тип std::ostringstream) было выделено статическим хранилищем. Разве это не означает, что объект должен оставаться в памяти до тех пор, пока программа не завершится? И если да, то почему нельзя получить доступ к строке?

ответ

11

strdup выделяет копию строки в куче, которую вы должны освободить вручную позже (с free() я думаю). Если у вас есть опция, было бы гораздо лучше вернуть std::string.

Статическое хранилище out не помогает, потому что .str() возвращает временный std::string, который разрушается при выходе из функции.

-1

В GetHandStateBrief переменный out не должен быть статическим. Вам нужно явное static string заменить временный, который создается в оригинальном вызове out.str():

static std::string outStr; 
std::ostringstream out; 
... rest of function ... 
outStr = out.str(); 
return outStr.c_str(); 
+1

Это рискованно. Возвращаемый символ 'char *' не гарантированно будет действительным после последующего вызова 'GetHandStateBrief'. –

+0

Верно, что каждый вызов 'GetHandStateBrief' приведет к аннулированию указателя, возвращенного предыдущим вызовом. Однако риск зависит от контекста. –

+1

downvote за риск выстрелить себе в ногу? –

0

strdup() возвращает символ * указатель, который указывает на память в куче. Вам нужно освободить(), когда вы закончите с этим, но да, это сработает.

Статическая локальная переменная std::ostringstream out не имеет смысла в этом случае, если только возвращаемая std :: string не является статической, что ваше наблюдение показывает, что оно неверно.

3

Вы правы, что out - это статическая переменная, выделенная для сегмента данных. Но out.str() является временным выделенным в стеке. Поэтому, когда вы делаете return out.str().c_str(), вы возвращаете указатель на внутренние данные временного стека. Обратите внимание, что даже если строка не является переменной стека, c_str «предоставляется только для того, чтобы оставаться неизменной до следующего вызова функции непостоянного члена строкового объекта».

Я думаю, вы попали на разумное обходное решение, предполагая, что вы не можете просто вернуть строку.

+2

Хмм, «статическая переменная, выделенная на куче» - никогда не слышала о такой штуке :) –

+0

Спасибо, что поймал это. –

+3

Ну, символьные данные строки действительно хранятся в куче с любой std :: string, статичной или любой другой. Это дескриптор строки, хранящийся в сегменте данных, как и другие переменные с глобальным временем жизни. –

Смежные вопросы