Czy następujący (wymyślony przykład) jest w porządku, czy jest to niezdefiniowane zachowanie:
// undefined behavior?
const auto& c = SomeClass{};
// use c in code later
const auto& v = c.GetSomeVariable();
źródło
Czy następujący (wymyślony przykład) jest w porządku, czy jest to niezdefiniowane zachowanie:
// undefined behavior?
const auto& c = SomeClass{};
// use c in code later
const auto& v = c.GetSomeVariable();
To jest bezpieczne. Const ref przedłuża czas życia tymczasowego. Zakres będzie zakresem stałej ref.
Życia tymczasowego obiektu może być przedłużony przez wiązanie z odniesieniem const lwartości lub odnośnik RValue (od C ++, 11), patrz inicjalizacji odniesienia dla szczegółów.
Ilekroć odniesienie jest powiązane z tymczasowym lub jego podobiektywem, jego żywotność jest przedłużana, aby pasowała do żywotności referencyjnego, z następującymi: wyjątkami :
- tymczasowe powiązanie z wartością zwrotną funkcji w instrukcji return nie jest przedłużane: jest niszczone natychmiast na końcu wyrażenia return. Taka funkcja zawsze zwraca zwisające odwołanie.
- tymczasowe powiązanie z elementem referencyjnym na liście inicjalizatora konstruktora trwa tylko do momentu wyjścia konstruktora, dopóki obiekt nie istnieje. (uwaga: taka inicjalizacja jest źle sformułowana od DR 1696).
- tymczasowe powiązanie z parametrem odwołania w wywołaniu funkcji istnieje do końca pełnego wyrażenia zawierającego to wywołanie funkcji: jeśli funkcja zwróci odwołanie, które przeżywa pełne wyrażenie, staje się odwołaniem wiszącym.
- tymczasowe powiązanie z odwołaniem w inicjalizatorze zastosowanym w nowym wyrażeniu istnieje do końca pełnego wyrażenia zawierającego to nowe wyrażenie, nie tak długo jak zainicjowany obiekt. Jeśli zainicjowany obiekt przeżywa pełne wyrażenie, jego element odniesienia staje się odwołaniem wiszącym.
- tymczasowe powiązanie z referencją w elemencie referencyjnym agregatu zainicjowanego przy użyciu składni inicjalizacji bezpośredniej (nawiasy) w przeciwieństwie do składni inicjalizacji listy (nawiasy klamrowe) istnieje do końca pełnego wyrażenia zawierającego inicjator.
struct A { int&& r; }; A a1{7}; // OK, lifetime is extended A a2(7); // well-formed, but dangling reference
Zasadniczo czas życia tymczasowego nie może być dalej przedłużany przez „przekazanie go”: drugie odniesienie, zainicjowane z odniesienia, z którym związany był tymczasowy, nie wpływa na jego żywotność.
jak zauważył @Konrad Rudolph (i patrz ostatni akapit powyżej):
„Jeśli
c.GetSomeVariable()
zwraca odwołanie do obiektu lokalnego lub odwołanie, że sam przedłuża żywotność jakiegoś obiektu, rozszerzenie życia nie uruchamia się”
c.GetSomeVariable()
zwraca odwołanie do obiektu lokalnego lub odniesienie, że sam przedłuża czas życia jakiegoś obiektu, przedłużenie czasu życia nie jest uruchamiane.Dzięki temu nie powinno być problemu dzięki przedłużeniu okresu użytkowania . Nowo wybudowany obiekt przetrwa, dopóki odniesienie nie będzie poza zasięgiem.
źródło
Tak, jest to całkowicie bezpieczne: powiązanie z
const
odniesieniem wydłuża czas jego użytkowania do zakresu tego odniesienia.Zauważ, że zachowanie nie jest przechodnie . Na przykład za pomocą
cc
wisi.źródło
To jest bezpieczne.
źródło
W tym konkretnym przypadku jest bezpieczny. Zauważ jednak, że nie wszystkie tymczasowe są bezpieczne na przykład na podstawie stałej referencji ...
Odwołanie uzyskane dla
z
NIE jest bezpieczne w użyciu, ponieważ tymczasowa instancja zostanie zniszczona pod koniec pełnego wyrażenia, przed osiągnięciemprintf
instrukcji. Dane wyjściowe to:źródło