Dlaczego to:
#include <string>
#include <iostream>
using namespace std;
class Sandbox
{
public:
Sandbox(const string& n) : member(n) {}
const string& member;
};
int main()
{
Sandbox sandbox(string("four"));
cout << "The answer is: " << sandbox.member << endl;
return 0;
}
Podaj wynik:
Odpowiedź to:
Zamiast:
Odpowiedź brzmi: cztery
cout << "The answer is: " << Sandbox(string("four")).member << endl;
, to na pewno zadziała.SandBox::member
jest czytany, tymczasowy ciąg jest nadal żywy .string("four")
jest niszczony na końcu pełnego wyrażenia, a nie po zamknięciuSandbox
konstruktora? Odpowiedź Potatoswatter mówi, że tymczasowe powiązanie z elementem referencyjnym w inicjatorze ctor konstruktora (§12.6.2 [class.base.init]) utrzymuje się do momentu zakończenia konstruktora.Odpowiedzi:
Tylko lokalne
const
referencje przedłużają żywotność.Norma określa takie zachowanie w §8.5.3 / 5, [dcl.init.ref], sekcja dotycząca inicjatorów deklaracji referencyjnych. Odwołanie w twoim przykładzie jest powiązane z argumentem konstruktora
n
i staje się nieprawidłowe, gdy obiektn
jest powiązany z wyjściem poza zakres.Rozszerzenie okresu istnienia nie jest przechodnie przez argument funkcji. §12.2 / 5 [klasa.czasowa]:
źródło
member
jest to związane z tymczasowym, ponieważ inicjalizacjamember
zan
pomocą środków wiążących sięmember
z tym samym obiektemn
jest związana z tym samym obiektem i jest to w rzeczywistości obiekt tymczasowy w tym przypadku.const
kwantyfikatora.Oto najprostszy sposób, aby wyjaśnić, co się stało:
W main () utworzyłeś łańcuch i przekazałeś go do konstruktora. To wystąpienie ciągu istniało tylko w konstruktorze. Wewnątrz konstruktora przypisałeś elementowi członkowskiemu bezpośrednie wskazywanie tego wystąpienia. Gdy zakres opuścił konstruktora, wystąpienie ciągu zostało zniszczone, a element członkowski wskazał obiekt ciągu, który już nie istnieje. Jeśli Sandbox.member wskazuje odwołanie poza jego zakresem, nie będzie w zasięgu tych zewnętrznych wystąpień.
Jeśli chcesz naprawić program, aby wyświetlał pożądane zachowanie, wprowadź następujące zmiany:
Teraz temp wyjdzie poza zakres na końcu main () zamiast na końcu konstruktora. Jest to jednak zła praktyka. Twoja zmienna składowa nigdy nie powinna być odniesieniem do zmiennej, która istnieje poza instancją. W praktyce nigdy nie wiadomo, kiedy ta zmienna wyjdzie poza zakres.
Polecam zdefiniowanie Sandbox.member jako parametru
const string member;
Spowoduje to skopiowanie danych tymczasowego parametru do zmiennej składowej zamiast przypisywania zmiennej składowej jako samego parametru tymczasowego.źródło
const string & temp = string("four"); Sandbox sandbox(temp); cout << sandbox.member << endl;
czy to nadal będzie działać?const string &temp = string("four");
daje ten sam wynik, coconst string temp("four");
, chyba że używaszdecltype(temp)
specjalnieHowever, this is bad practice.
- czemu? Jeśli zarówno obiekt tymczasowy, jak i obiekt zawierający używają automatycznego przechowywania w tym samym zakresie, czy nie jest to w 100% bezpieczne? A jeśli tego nie zrobisz, co byś zrobił, jeśli ciąg jest zbyt duży i zbyt drogi do skopiowania?Technicznie rzecz biorąc, ten program nie jest wymagany do wysyłania czegokolwiek na standardowe wyjście (które na początku jest buforowanym strumieniem).
cout << "The answer is: "
Nieco emituje"The answer is: "
w buforze o standardowe wyjście.Wtedy
<< sandbox.member
bit dostarczy wiszące odniesienie dooperator << (ostream &, const std::string &)
, które wywoła niezdefiniowane zachowanie .Z tego powodu nic nie jest gwarantowane. Program może działać pozornie dobrze lub może ulec awarii nawet bez opróżniania wyjścia standardowego - co oznacza, że tekst „Odpowiedź brzmi:” nie pojawił się na ekranie.
źródło
"The answer is: "
zostanie to zapisane w dowolnym miejscu.Ponieważ twój tymczasowy ciąg wyszedł poza zakres po zwróceniu konstruktora Sandbox, a zajmowany przez niego stos został odzyskany do innych celów.
Ogólnie rzecz biorąc, nigdy nie należy długo przechowywać referencji. Odwołania są dobre dla argumentów lub zmiennych lokalnych, nigdy dla członków klasy.
źródło
odnosisz się do czegoś, co zniknęło. Poniższe będą działać
źródło