2013-08-09 12 views
36

Ho testato questo codice:È sicuro usare (str1 + str2) .c_str()?

#include <iostream> 
#include <cstdio> 
#include <string> 
using namespace std; 

int main() 
{ 
    string s1("a"),s2("b"); 
    const char * s = (s1+s2).c_str(); 
    printf("%s\n",s); 
} 

Esso restituisce "ab".

Per quanto ne so, dal momento che (s1 +s2) è un oggetto temporaneo e potrebbe scomparire in qualche modo (non ne ho idea), quindi const char * s potrebbe puntare alla memoria indefinita e potrebbe essere scaricato.

Quindi è sicuro utilizzare lo .c_str() in questo modo?

+1

Inserire 'string s3 (" Oh no! ");' Appena prima della stampa, è probabile che l'output cambierà. (Ma non è garantito.) – Mat

+4

Il "possibile duplicato" è fondamentalmente diverso (utilizzare all'interno della stessa espressione completa) – MSalters

risposta

57

Nel tuo esempio non è sicuro. È sicuro tuttavia in

printf("%s\n", (a + b).c_str()); 

La ragione è che i valori temporanei (come il risultato di a + b) vengono distrutte alla fine della piena espressione. Nel tuo esempio il const char * sopravvive all'espressione completa che contiene il temporaneo e il dereferenziamento è un comportamento non definito.

La parte peggiore del "comportamento indefinito" è che le cose possono apparentemente funzionare comunque ... (codice di UB si blocca solo se si sta facendo il vostro demo di fronte a un vasto pubblico che include i tuoi genitori ;-))

+9

Riconosco alcuni ricordi dolorosi lì? ;) – catchmeifyoutry

+1

Puoi indicare dove "i valori temporanei (come il risultato di un + b) vengono distrutti alla fine dell'espressione completa." È specificato nelle specifiche? – SheetJS

+0

@Nirk vedi la risposta di Pierre Fourgeaud per il testo standard. –

29

in questo esempio si può citare solo lo standard:

12.2 oggetti temporanei [class.temporary]

oggetti temporanei vengono distrutti come ultimo passaggio nella valutazione pieno-espressione (1.9) che (lessicalmente) contenere s il punto in cui sono stati creati. Questo è vero anche se la valutazione termina con il lancio di un'eccezione. I calcoli del valore e gli effetti collaterali della distruzione di un oggetto temporaneo sono associati solo all'espressione completa, non a una sottoespressione specifica.

cioè dopo il punto e virgola della vostra linea:

const char * s = (s1+s2).c_str(); // <- Here 

Così qui:

printf("%s\n",s); // This line will now cause undefined behaviour. 

Perché? Perché, come l'oggetto è destructed, non si sa più quello che è in questo luogo ora ...

La cosa brutta è che, con un comportamento indefinito , il programma può sembrare a lavorare per la prima volta, ma ... si andrà in crash con certezza nel momento peggiore ...

si può fare:

printf("%s\n", (s1+s2).c_str()); 

che funzionerà perché l'oggetto non viene distrutto ancora (ricordate, dopo il punto e virgola ...).

+0

Non c'è nessuna cancellazione qui; la parola è "destructed". (In C++, hanno significati diversi.) –

+0

@JamesKanze Hai ragione! L'ho appena corretto! Grazie per aver segnalato questo! –

5

non è sicuro, ma si può facilmente assegnare ad una nuova variabile, e il puntatore sarà al sicuro nel campo di applicazione di tale variabile:

string s1("a"), s2("b") , s3; 
s3 = s1 + s2; 
printf("%s\n", s3.c_str()); 

//other operations with s3 
4

Come la maggior parte costrutti di programmazione, è "sicuro" se si utilizza correttamente, e non è "sicuro" se sei sciatto. In questo caso, usarlo correttamente significa prestare attenzione alle vite degli oggetti.L'operatore + crea un oggetto temporaneo che viene distrutto alla fine dell'istruzione e il reso const char* non è più valido dopo l'istruzione che lo ha creato. Quindi è possibile passare il risultato di c_str() direttamente a una funzione, ma non è possibile salvare il puntatore e utilizzarlo in seguito.

Problemi correlati