Warum macht das:
#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;
}
Geben Sie die Ausgabe von:
Die Antwort ist:
Anstatt:
Die Antwort lautet: vier
cout << "The answer is: " << Sandbox(string("four")).member << endl;
, dann würde es garantiert funktionieren.SandBox::member
ist die temporäre Zeichenfolge also noch lebendig, wenn sie gelesen wird .string("four")
am Ende des vollständigen Ausdrucks und nicht nach dem Beenden desSandbox
Konstruktors zerstört wird? Die Antwort von Potatoswatter lautet: Eine temporäre Bindung an ein Referenzelement im ctor-Initialisierer eines Konstruktors (§12.6.2 [class.base.init]) bleibt bestehen, bis der Konstruktor beendet wird.Antworten:
Nur lokale
const
Referenzen verlängern die Lebensdauer.Der Standard spezifiziert ein solches Verhalten in §8.5.3 / 5, [dcl.init.ref], dem Abschnitt über Initialisierer von Referenzdeklarationen. Die Referenz in Ihrem Beispiel ist an das Argument des Konstruktors gebunden
n
und wird ungültig, wenn das Objektn
außerhalb des Gültigkeitsbereichs liegt.Die Lebensdauerverlängerung ist nicht durch ein Funktionsargument transitiv. §12.2 / 5 [class.temporary]:
quelle
member
an ein temporäres Objekt gebunden ist , da das Initialisierenmember
mitn
Mitteln zum Bindenmember
an dasselbe Objektn
an ein temporäres Objekt gebunden ist und dies in diesem Fall tatsächlich ein temporäres Objekt ist.const
Systems, ohne dass ein Quaifier erforderlich ist.Hier ist der einfachste Weg, um zu erklären, was passiert ist:
In main () haben Sie eine Zeichenfolge erstellt und an den Konstruktor übergeben. Diese Zeichenfolgeninstanz war nur im Konstruktor vorhanden. Innerhalb des Konstruktors haben Sie ein Mitglied zugewiesen, das direkt auf diese Instanz verweist. Als der Bereich den Konstruktor verließ, wurde die Zeichenfolgeninstanz zerstört, und das Mitglied zeigte auf ein Zeichenfolgenobjekt, das nicht mehr vorhanden war. Wenn Sandbox.member auf eine Referenz außerhalb seines Gültigkeitsbereichs verweist, werden diese externen Instanzen nicht im Gültigkeitsbereich gespeichert.
Wenn Sie Ihr Programm so reparieren möchten, dass das gewünschte Verhalten angezeigt wird, nehmen Sie die folgenden Änderungen vor:
Jetzt wird temp am Ende von main () anstatt am Ende des Konstruktors nicht mehr gültig sein. Dies ist jedoch eine schlechte Praxis. Ihre Mitgliedsvariable sollte niemals ein Verweis auf eine Variable sein, die außerhalb der Instanz existiert. In der Praxis wissen Sie nie, wann diese Variable den Gültigkeitsbereich verlässt.
Ich empfehle, Sandbox.member als zu definieren.
const string member;
Dadurch werden die Daten des temporären Parameters in die Membervariable kopiert, anstatt die Membervariable als temporären Parameter selbst zuzuweisen .quelle
const string & temp = string("four"); Sandbox sandbox(temp); cout << sandbox.member << endl;
Wird es noch funktionieren?const string &temp = string("four");
gibt das gleiche Ergebnis wieconst string temp("four");
, wenn Sie nichtdecltype(temp)
speziell verwendenHowever, this is bad practice.
- Warum? Wenn sowohl das temporäre als auch das enthaltende Objekt automatische Speicherung im selben Bereich verwenden, ist es nicht 100% sicher? Und wenn Sie das nicht tun, was würden Sie tun, wenn die Zeichenfolge zu groß und zu teuer zum Kopieren ist?Technisch gesehen ist dieses Programm nicht erforderlich, um tatsächlich etwas an die Standardausgabe auszugeben (dies ist zunächst ein gepufferter Stream).
Das
cout << "The answer is: "
Bit wird"The answer is: "
in den Puffer von stdout ausgegeben.Dann
<< sandbox.member
liefert das Bit die baumelnde Referenz inoperator << (ostream &, const std::string &)
, die undefiniertes Verhalten hervorruft .Aus diesem Grund ist garantiert nichts passiert. Das Programm funktioniert möglicherweise einwandfrei oder stürzt ab, ohne dass stdout gelöscht wird. Dies bedeutet, dass der Text "Die Antwort lautet:" nicht auf Ihrem Bildschirm angezeigt wird.
quelle
"The answer is: "
das irgendwo geschrieben wird.Da Ihre temporäre Zeichenfolge nach der Rückkehr des Sandbox-Konstruktors nicht mehr gültig war und der von ihm belegte Stapel für andere Zwecke zurückgefordert wurde.
Im Allgemeinen sollten Sie Referenzen niemals langfristig aufbewahren. Referenzen sind gut für Argumente oder lokale Variablen, niemals für Klassenmitglieder.
quelle
Sie beziehen sich auf etwas, das verschwunden ist. Folgendes wird funktionieren
quelle