2010-04-17 12 views
8

Questo è da una piccola libreria che ho trovato in rete:Tornando 'c_str' da una funzione

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

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

    return out.str().c_str() 
} 

Nel mio codice sto facendo questo:

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

Ora, immondizia contenuta prima d . Mi sono poi reso conto che la stringa C che ottengo dalla funzione viene distrutta quando la funzione ritorna perché lo stack std::ostringstream è allocato. Così ho aggiunto:

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

E ora posso ottenere il testo che mi serve dalla funzione.

Ho due domande:

  1. Perchè sono la comprensione di questo correttamente?

  2. Successivamente ho notato che out (di tipo std::ostringstream) è stato allocato con memoria statica. Questo non significa che l'oggetto dovrebbe rimanere in memoria fino alla fine del programma? E se sì, allora perché non si può accedere alla stringa?

risposta

11

strdup alloca una copia della stringa sul mucchio, che si deve liberare manualmente in seguito (con free() credo). Se hai l'opzione, sarebbe molto meglio restituire std::string.

L'archiviazione statica dinon è di aiuto, poiché .str() restituisce un valore temporaneo std::string, che viene distrutto quando la funzione viene chiusa.

-1

In GetHandStateBrief, la variabile out non deve essere statica. Avete bisogno di un esplicito static string per sostituire la temporanea che si stava creando nella chiamata originale a out.str():

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

Questo è rischioso. Il 'char * restituito non è garantito per essere valido dopo una successiva chiamata a' GetHandStateBrief'. –

+0

Vero che ogni chiamata a 'GetHandStateBrief' invaliderà il puntatore restituito dalla chiamata precedente. Il rischio è comunque dipendente dal contesto. –

+1

downvote per il rischio di spararti ai piedi? –

0

strdup() restituisce un puntatore char * che punta alla memoria sul mucchio. Hai bisogno di liberarlo() quando hai finito, ma sì, funzionerà.

La variabile locale statica std::ostringstream out non ha senso in questo caso, a meno che la std :: string che viene restituita sia anche statica, che l'osservazione mostra essere non vera.

3

Hai ragione che out è una variabile statica allocata sul segmento di dati. Ma out.str() è un temporaneo allocato nello stack. Quindi quando fai return out.str().c_str() stai restituendo un puntatore ai dati interni di uno stack temporaneo. Si noti che anche se una stringa non è una variabile stack, c_str è "concesso solo per rimanere invariato fino alla prossima chiamata a una funzione membro non costante dell'oggetto stringa".

Penso che abbiate trovato una soluzione ragionevole, supponendo che non sia possibile restituire una stringa.

+2

Hmm, "variabile statica allocata nell'heap" - mai sentito parlare di questa cosa :) –

+0

Grazie per averlo capito. –

+3

Bene, i dati di carattere della stringa sono effettivamente memorizzati nell'heap con qualsiasi std :: string, sia statico che altro. È il descrittore di stringhe memorizzato nel segmento dati come altre variabili con durata globale. –