2012-10-18 16 views
7

Mam raczej podstawowe C++ pytanie, rozważmy funkcję, która pobiera niektóre parametry wejściowe i tworzy std::string które z tych parametrów, takich jak ten poniżej:C++ powrocie tymczasowe obiekty zamieszanie

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? 
} 

Rozumiem, że stringstream-object wyjdzie poza zakres, gdy funkcja zwróci, ale czy nie spowoduje to również unieważnienia konstruowanego łańcucha?

Co się stanie, jeśli zmienię typ zwrotu na const char * i zamiast tego zwrócę numer ss.str().c_str()?

Wygląda na to, że powyższy kod działa, ale podejrzewam, że dzieje się tak dlatego, że pamięć zawierająca "tymczasowy" obiekt nie została jeszcze zastąpiona przez coś innego, kiedy go używam?

Muszę przyznać, jestem raczej zdezorientowany w takich sytuacjach w ogóle, byłbym wdzięczny, gdyby ktoś mógł wyjaśnić te "tymczasowe przedmioty" - coś dla mnie (lub po prostu wskazać mi właściwy kierunek).

thx z góry

Odpowiedz

10

Wracasz tymczasowy obiekt, ale ponieważ go zwrócić przez wartość, tworzona jest kopia. Jeśli zwrócisz wskaźnik lub odniesienie do obiektu tymczasowego, byłby to błąd.

Jeśli zmienić typ zwracany do const char * i powrócić ss.str().c_str() byś wrócić wskaźnik do jakiegoś bufora czasowego std::string zwróconej przez ss.str() a to byłoby złe.

2

Jak widać Stringstream::str() zwraca obiekt . Zwracamy std::string bez odniesienia, co oznacza, że ​​bez konstruktora optymalizacji RVO (NRVO) konstruktor kopiowania wywoła i utworzy poprawny obiekt std::string. Dzięki optymalizacji std::string zostanie przeniesiony bez konstruktora kopiowania. Ale jeśli zwróci std::string&, ulegnie awarii, ponieważ obiekt ten zostanie zniszczony po powrocie funkcji. Ten sam efekt będzie z const char *, ponieważ po zniszczeniu ten wskaźnik wskaże na złą pamięć i jest to niebezpieczna sytuacja.

+0

Zostanie wywołany destruktor po tym, jak ta kopia nie zostanie pobrana przez wywołanie funkcji constructString? Ponieważ jest to obiekt tymczasowy, zakładam, że wskaźnik jest przechowywany na stosie jako wartość zwracana. Co dzieje się po zwrocie? Czy zostanie zniszczony, jeśli nie ma nowego właściciela obiektu? Jak kompilator wie, że obiekt musi zostać zniszczony po jego zwróceniu? –

1

Założono: T val = some_function(), po zwróceniu wartości z some_function C++ skopiuj wartość zwróconej wartości do val, używając określonego konstruktora kopiowania lub wbudowanego operatora. Więc jeśli zwrócisz int lub std::string, nie ma problemu, ale jeśli zwrócisz wskaźnik do pamięci, która zostanie zwolniona na końcu funkcji, oops !! twój wskaźnik zostanie wskazany na nieprawidłową pamięć. Na przykład rozważ to:

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

wracasz wskaźnik do danych, które zostaną uwolnione, jak tylko powrót funkcji (od res zostaną zniszczone i będzie uwolnić swoje dane wewnętrzne), więc dostaniesz adres, ale to adres nie wskazuje na to, czego się spodziewasz!

+0

* "C++ kopiuje wartość zwróconej wartości do wartości" * - Co więcej, już kopiuje wartość zwróconą przez 'ss.str()' do wartości zwracanej przez funkcję, ponieważ zwraca wartość-by. Tak by działało nawet z 'const T & val = some_function()', biorąc pod uwagę 'some_function' zwraca wartość-by. –

+1

'const T & val = some_function()' faktycznie działa idealnie, ponieważ C++ kopiuje wszystko według wartości, a 'const T &' jest w rzeczywistości 'const T *' z pewną inną semantyczną, problemem tutaj jest 'const T & 'wskazuje na lokalizację to zostanie unieważnione po zakończeniu wywołania funkcji! – BigBoss

+1

Nie, nie będzie, ponieważ powiązanie odwołania stałego do tymczasowego wydłuża czas życia tymczasowego. Właśnie dlatego 'void foo (const std :: string &); foo ("test"); "działa idealnie dobrze. Nie będzie jednak działać dla wskaźnika (lub odniesienia nie-const). Jest to jedna z niewielkich różnic, które zawierają odniesienia do czegoś innego niż syntaktyczny cukier do wskaźników. –