2010-04-17 3 views
8

Diese von einer kleinen Bibliothek, die ich online gefunden:Rückkehr 'c_str' aus einer Funktion

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

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

    return out.str().c_str() 
} 

In meinem Code tue dies:

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

nun auf dem ersten d enthaltenen Müll . Ich erkannte dann, dass die C-Zeichenfolge, die ich von der Funktion bekomme, zerstört wird, wenn die Funktion zurückkehrt, weil std::ostringstream auf dem Stapel zugeordnet ist. Also fügte ich hinzu:

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

Und jetzt kann ich den Text, den ich von der Funktion brauche.

Ich habe zwei Fragen:

  1. Bin ich richtig verstehen das?

  2. Ich bemerkte später, dass out (vom Typ std::ostringstream) mit statischem Speicher zugewiesen wurde. Bedeutet das nicht, dass das Objekt im Speicher bleiben soll, bis das Programm beendet wird? Und wenn ja, warum kann dann nicht auf die Zeichenkette zugegriffen werden?

Antwort

11

strdup ordnet eine Kopie des Strings auf dem Heap, die Sie manuell später befreien müssen (mit free() glaube ich). Wenn Sie die Option haben, wäre es viel besser, std::string zurückzugeben.

Der statische Speicher von out hilft nicht, weil .str() eine temporäre std::string zurückgibt, die zerstört wird, wenn die Funktion beendet wird.

-1

In GetHandStateBrief muss die Variable out nicht statisch sein. Sie müssen eine explizite static string die temporäre zu ersetzen, die in den ursprünglichen Anruf out.str() erstellt wurde:

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

Dies ist riskant. Das zurückgegebene 'char *' ist nach einem nachfolgenden Aufruf von 'GetHandStateBrief' nicht garantiert gültig. –

+0

Es stimmt, dass jeder Aufruf von "GetHandStateBrief" den vom vorherigen Aufruf zurückgegebenen Zeiger ungültig macht. Das Risiko ist jedoch kontextabhängig. –

+1

Downvote für das Risiko, sich in den Fuß zu schießen? –

0

strdup() gibt einen char * Zeiger, der auf dem Heap-Speicher zeigt. Du musst es befreien(), wenn du damit fertig bist, aber ja, das wird funktionieren.

Die statische lokale Variable std::ostringstream out macht in diesem Fall keinen Sinn, es sei denn, die zurückgegebene std :: string ist ebenfalls statisch, was sich bei Ihrer Beobachtung als nicht wahr erweist.

3

Sie haben Recht, dass out eine statische Variable ist, die dem Datensegment zugeordnet ist. Aber out.str() ist eine temporäre auf dem Stapel zugeordnet. Wenn Sie also return out.str().c_str() tun, geben Sie einen Zeiger auf die internen Daten eines Stack-Temporärs zurück. Beachten Sie, dass c_str "nur gewährt wird, um bis zum nächsten Aufruf einer nicht konstanten Elementfunktion des Zeichenfolgenobjekts unverändert zu bleiben", selbst wenn eine Zeichenfolge keine Stapelvariable ist.

Ich denke, Sie haben eine vernünftige Lösung gefunden, vorausgesetzt, Sie können nicht einfach eine Zeichenfolge zurückgeben.

+2

Hmm, "statische Variable auf dem Heap zugewiesen" - noch nie von so etwas gehört :) –

+0

Danke für den Fang. –

+3

Nun, die Zeichendaten der Zeichenfolge ist tatsächlich auf dem Heap mit einem beliebigen std :: string gespeichert, ob statisch oder was auch immer. Es ist der String-Deskriptor, der wie andere Variablen mit globaler Lebensdauer im Datensegment gespeichert ist. –