2010-04-17 30 views
8

Se trata de una pequeña biblioteca que he encontrado en Internet:Volviendo 'c_str' de una función

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

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

    return out.str().c_str() 
} 

En mi código que estoy haciendo esto:

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

Ahora, en un primer momento d basura contenida . Luego me di cuenta de que la cadena C que obtengo de la función se destruye cuando la función regresa porque std::ostringstream está asignado en la pila. Por lo que añade:

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

Y ahora puedo obtener el texto que necesito de la función.

Tengo dos preguntas:

  1. Estoy entendiendo esto correctamente?

  2. Más tarde noté que out (del tipo std::ostringstream) se asignó con el almacenamiento estático. ¿No significa eso que se supone que el objeto permanecerá en la memoria hasta que el programa termine? Y si es así, ¿por qué no se puede acceder a la cadena?

Respuesta

11

strdup asigna una copia de la cadena en el montón, lo que usted tiene que liberar manualmente más tarde (con free() creo). Si tiene la opción, sería mucho mejor devolver std::string.

El almacenamiento estático de out no ayuda, porque .str() devuelve un std::string temporal, que se destruye cuando la función finaliza.

-1

En GetHandStateBrief, la variable out no necesita ser estática. Es necesario un compromiso explícito static string para reemplazar el temporal que se está creando en la llamada original a out.str():

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

Esto es arriesgado. El '' char * 'devuelto no se garantiza que sea válido después de una llamada subsiguiente a' GetHandStateBrief'. –

+0

Es cierto que cada llamada a 'GetHandStateBrief' invalidará el puntero devuelto por la llamada anterior. Sin embargo, el riesgo depende del contexto. –

+1

downvote por el riesgo de dispararse en el pie? –

0

strdup() devuelve un puntero char * que apunta a la memoria en el montón. Necesita liberarlo() cuando haya terminado con él, pero sí, eso funcionará.

La variable local estática std::ostringstream out no tiene sentido en este caso, a menos que la cadena std :: que se devuelve también sea estática y su observación muestre que no es verdadera.

3

Tiene razón en que out es una variable estática asignada en el segmento de datos. Pero out.str() es un temporal asignado en la pila. Entonces cuando haces return out.str().c_str() estás devolviendo un puntero a los datos internos de una pila temporal. Tenga en cuenta que incluso si una cadena no es una variable de pila, c_str "solo se concede para permanecer sin cambios hasta la siguiente llamada a una función de miembro no constante del objeto de cadena".

Creo que ha llegado a una solución razonable, suponiendo que no puede simplemente devolver una cadena.

+2

Hmm, "variable estática asignada en el montón" - nunca he oído hablar de tal cosa :) –

+0

Gracias por capturar eso. –

+3

Bueno, los datos de caracteres de la cadena de hecho están almacenados en el montón con cualquier std :: string, ya sea estática o lo que sea. Es el descriptor de cadena almacenado en el segmento de datos como otras variables con duración global. –

Cuestiones relacionadas