Czy można zwracać domyślną wartość argumentu przez odwołanie do stałej, jak w poniższych przykładach:
https://coliru.stacked-crooked.com/a/ff76e060a007723b
#include <string>
const std::string& foo(const std::string& s = std::string(""))
{
return s;
}
int main()
{
const std::string& s1 = foo();
std::string s2 = foo();
const std::string& s3 = foo("s");
std::string s4 = foo("s");
}
c++
language-lawyer
object-lifetime
default-arguments
reference-binding
Zamrożone serce
źródło
źródło
std::string
na własny, abyś mógł śledzić budowę i zniszczenie.Odpowiedzi:
W kodzie, jak
s1
is3
są zwisające referencje.s2
is4
są w porządku.W pierwszym wywołaniu tymczasowy pusty
std::string
obiekt utworzony z domyślnego argumentu zostanie utworzony w kontekście wyrażenia zawierającego wywołanie. Dlatego umrze pod koniec definicjis1
, która pozostawias1
zwisające.W drugim wywołaniu
std::string
obiekt tymczasowy służy do inicjalizacjis2
, a następnie umiera.W trzecim wywołaniu literał łańcuchowy
"s"
jest używany do utworzeniastd::string
obiektu tymczasowego, który również umiera na końcu definicjis3
, pozostawiającs3
zwisające.W czwartym wywołaniu tymczasowy
std::string
obiekt z wartością"s"
jest używany do inicjalizacji,s4
a następnie umiera.Zobacz C ++ 17 [współczesna klasa] / 6.1
źródło
To nie jest bezpieczne :
źródło
std::string s2 = foo();
jest to poprawne (w końcu żadne odniesienie nie jest jawnie przekazywane)?To zależy od tego, co zrobisz z łańcuchem później.
Jeśli masz pytanie, czy mój kod jest poprawny? więc tak to jest.
Z [dcl.fct.default] / 2
Twój kod jest więc faktycznie równoważny z:
Cały kod jest poprawny, ale w żadnym z tych przypadków nie ma przedłużenia czasu życia referencji, ponieważ typ zwracany jest referencją.
Ponieważ wywołujesz funkcję tymczasową, czas życia zwracanego ciągu nie wydłuży instrukcji.
Twój przykład z
s2
jest w porządku, ponieważ kopiujesz (lub przenosisz) z tymczasowego przed końcem sytości.s3
ma taki sam problem jaks1
.źródło