2012-10-18 12 views
7

Ho una base C++ domanda un po ', si consideri una funzione che prende alcuni parametri di input e crea un std::string che da quei parametri come quella qui sotto:C++ ritorno oggetti temporanei confusione

std::string constructString(int some_parameter) { 

    std::stringstream ss; 

    // Construct a string (arbitrarily complex) 
    ss << "Some parameter is " << some_parameter << " right now"; 

    return ss.str(); //Am I not returning a temporary object here? 
} 

Capisco che il stringstream-object uscirà dall'ambito quando la funzione ritorna, ma ciò non invalida anche la stringa costruita?

Cosa accadrebbe se cambiassi il tipo di ritorno su const char * e restituissi invece ss.str().c_str()?

Il codice come sopra sembra funzionare, ma ho il sospetto che sia solo perché la memoria contenente l'oggetto "temporaneo" non è stata ancora sovrascritta con qualcos'altro quando la uso?

Devo ammettere, sono piuttosto confuso in tali situazioni in generale, sarei grato se qualcuno potesse spiegare tutto questo "oggetti temporanei", tutto per me (o semplicemente indicarmi la giusta direzione).

thx in anticipo

risposta

10

si restituisce un oggetto temporaneo, ma perché lo restituite per valore, viene creata la copia. Se si restituisce un puntatore o un riferimento a un oggetto temporaneo, sarebbe un errore.

Se si cambia il tipo di ritorno per const char * e tornare ss.str().c_str() si sarebbe tornare puntatore ad alcuni buffer temporaneo std::string restituito da ss.str() e che sarebbe male.

2

Come si vede Stringstream::str() restituisce std::string oggetto. Si restituisce std::string senza riferimento che significa che senza RVO (NRVO) il costruttore di copie di ottimizzazione chiamerà e creerà un oggetto valido std::string. Con l'ottimizzazione std::string verrà spostato senza il costruttore di copie. Ma se restituirà std::string& si bloccherà perché questo oggetto sarà distrutto dopo il ritorno della funzione. Lo stesso effetto sarà con const char * perché dopo aver distrutto questo puntatore si punta sulla memoria errata e questa è una situazione pericolosa.

+0

Sarà chiamato distruttore dopo che questa copia non verrà rilevata dalla funzione chiamata constructString? Dato che si tratta di un oggetto temporaneo, suppongo che il puntatore sia tenuto in pila come valore di ritorno. Cosa succede dopo che è stato restituito? Viene distrutto se non c'è un nuovo proprietario dell'oggetto? Come il compilatore sa che l'oggetto deve essere distrutto o no dopo che è stato restituito? –

1

Si supponga che: T val = some_function(), quando si restituisce un valore da some_function valore di copia C++ del valore restituito in val utilizzando il costruttore di copia specificato o l'operatore incorporato. Quindi se si restituisce uno int o std::string non c'è alcun problema, ma se si restituisce un puntatore a una memoria che verrà liberata alla fine della funzione, oops !! il puntatore verrà indirizzato a una memoria non valida. Ad esempio si consideri questo:

const char* some_function() { 
    std::string res(...); 
    //... 
    return res.c_str(); 
} 

State ritornando puntatore ai dati che saranno liberati non appena ritorno della funzione (dal res saranno distrutti e libererà i suoi dati interni) in modo da otterrete l'indirizzo, ma che l'indirizzo non punta su ciò che ti aspetti!

+0

* "Valore di copia C++ del valore restituito in val" * - Ancora di più, copia già il valore restituito da 'ss.str()' nel valore di ritorno della funzione, poiché restituisce il valore-by. Quindi funzionerebbe anche con 'const T & val = some_function()', dato che 'some_function' restituisce in base al valore. –

+1

'const T & val = some_function()' funziona perfettamente, dal momento che C++ copia ogni cosa per valore e 'const T &' è in realtà 'const T *' con qualche semantica diversa, il problema qui è 'const T &' punta a una posizione che sarà invalidato dopo che la chiamata alla funzione è stata completata! – BigBoss

+1

No, non lo farà, perché legare un riferimento const a un temporaneo estende la durata del temporaneo. Ecco perché 'void foo (const std :: string &); foo ("test"); 'funziona perfettamente bene. Tuttavia, non funzionerà con un puntatore (o un riferimento non const). Questa è una delle piccole differenze, che rende i riferimenti effettivamente qualcosa di diverso dallo zucchero sintattico per i puntatori. –

Problemi correlati