Odpowiedzi:
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.
To jest bezpieczne.
[class.temporary]/5
: Istnieją trzy konteksty, w których elementy tymczasowe są niszczone w innym punkcie niż koniec pełnego wyrażenia . [..]
[class.temporary]/6
: Trzeci kontekst dotyczy powiązania odwołania z obiektem tymczasowym. Obiekt tymczasowy, z którym powiązane jest odniesienie, lub obiekt tymczasowy, który jest kompletnym obiektem podobiektu, z którym powiązane jest odniesienie, utrzymuje się przez cały okres istnienia odniesienia, jeśli wartość glvalue, z którą powiązane jest odniesienie, uzyskano w jeden z następujących sposobów : [wiele rzeczy tutaj]
W tym konkretnym przypadku jest bezpieczny. Zauważ jednak, że nie wszystkie tymczasowe są bezpieczne na przykład na podstawie stałej referencji ...
#include <stdio.h>
struct Foo {
int member;
Foo() : member(0) {
printf("Constructor\n");
}
~Foo() {
printf("Destructor\n");
}
const Foo& method() const {
return *this;
}
};
int main() {
{
const Foo& x = Foo{}; // safe
printf("here!\n");
}
{
const int& y = Foo{}.member; // safe too (special rule for this)
printf("here (2)!\n");
}
{
const Foo& z = Foo{}.method(); // NOT safe
printf("here (3)!\n");
}
return 0;
}
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ęciem printf
instrukcji. Dane wyjściowe to:
Constructor
here!
Destructor
Constructor
here (2)!
Destructor
Constructor
Destructor
here (3)!