Bietet C ++ eine Garantie für die Lebensdauer einer temporären Variablen, die innerhalb eines Funktionsaufrufs erstellt, aber nicht als Parameter verwendet wird? Hier ist eine Beispielklasse:
class StringBuffer
{
public:
StringBuffer(std::string & str) : m_str(str)
{
m_buffer.push_back(0);
}
~StringBuffer()
{
m_str = &m_buffer[0];
}
char * Size(int maxlength)
{
m_buffer.resize(maxlength + 1, 0);
return &m_buffer[0];
}
private:
std::string & m_str;
std::vector<char> m_buffer;
};
Und so würden Sie es verwenden:
// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);
std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
Wann wird der Destruktor für das temporäre StringBuffer-Objekt aufgerufen? Ist es:
- Vor dem Aufruf von GetString?
- Nachdem GetString zurückgekehrt ist?
- Compiler abhängig?
Ich weiß, dass C ++ garantiert, dass eine lokale temporäre Variable gültig ist, solange ein Verweis darauf vorhanden ist. Gilt dies für übergeordnete Objekte, wenn ein Verweis auf eine Mitgliedsvariable vorhanden ist?
Vielen Dank.
m_str.reserve(maxlength)
inchar * Size(int maxlength)
, sonst könnte der destructor werfen.Antworten:
Der Destruktor für diese Art von Temporären wird am Ende des vollständigen Ausdrucks aufgerufen. Das ist der äußerste Ausdruck, der nicht Teil eines anderen Ausdrucks ist. Dies ist in Ihrem Fall der Fall, nachdem die Funktion zurückgegeben und der Wert ausgewertet wurde. Also wird alles gut funktionieren.
Es ist in der Tat das, was Ausdrucksvorlagen zum Funktionieren bringt: Sie können Verweise auf diese Art von Temporären in einem Ausdruck wie enthalten
Weil jedes temporäre bis zum Ausdruck dauern wird
Wird komplett ausgewertet. Es ist
12.2 Temporary objects
im Standard ziemlich kurz beschrieben .quelle
printf("%s", strdup(std::string("$$$").c_str()) );
? Ich meine , wennstrdup(std::string("$$$").c_str())
als den vollen Ausdruck genommen wird, dann der Zeiger,strdup
ist sieht gültig . Wennstd::string("$$$").c_str()
ein voller Ausdruck ist, dass der Zeigerstrdup
sieht , ist ungültig ! Könnten Sie bitte anhand dieses Beispiels etwas mehr erklären?printf
ist der vollständige Ausdruck. Somitstrdup
ist das ein unnötiger Speicherverlust - Sie können es einfachc_str()
direkt drucken lassen .Die Antwort von litb ist richtig. Die Lebensdauer des temporären Objekts (auch als r-Wert bezeichnet) ist an den Ausdruck gebunden, und der Destruktor für das temporäre Objekt wird am Ende des vollständigen Ausdrucks aufgerufen. Wenn der Destruktor in StringBuffer aufgerufen wird, wird auch der Destruktor in m_buffer aufgerufen aufgerufen, aber nicht der Destruktor auf m_str, da es sich um eine Referenz handelt.
Beachten Sie, dass C ++ 0x die Dinge nur ein wenig ändert, da es rWertreferenzen hinzufügt und die Semantik verschiebt. Im Wesentlichen kann ich mithilfe eines r-Wert-Referenzparameters (notiert mit &&) den r-Wert in die Funktion 'verschieben' (anstatt ihn zu kopieren), und die Lebensdauer des r-Werts kann an das Objekt gebunden werden, in das er verschoben wird, nicht an den Ausdruck. Es gibt einen wirklich guten Blog-Beitrag des MSVC-Teams, der dies ausführlich durchläuft, und ich ermutige die Leute, ihn zu lesen.
Das pädagogische Beispiel für das Verschieben von Werten sind temporäre Zeichenfolgen, und ich werde die Zuordnung in einem Konstruktor zeigen. Wenn ich eine Klasse MyType habe, die eine String-Member-Variable enthält, kann sie mit einem r-Wert im Konstruktor wie folgt initialisiert werden:
Das ist schön, denn wenn ich eine Instanz dieser Klasse mit einem temporären Objekt deklariere:
Was passiert ist, dass wir vermeiden, das temporäre Objekt zu kopieren und zu zerstören und "Hallo" direkt in der Mitgliedsvariablen der besitzenden Klasseninstanz platziert wird. Wenn das Objekt schwerer als eine 'Zeichenfolge' ist, kann der zusätzliche Aufruf von Kopie und Destruktor von Bedeutung sein.
quelle
Nach dem Aufruf von GetString kehrt zurück.
quelle
StringBuffer befindet sich im Bereich von GetString. Es sollte am Ende des Bereichs von GetString zerstört werden (dh wenn es zurückkehrt). Ich glaube auch nicht, dass C ++ garantiert, dass eine Variable existiert, solange es eine Referenz gibt.
Folgendes sollte kompiliert werden:
quelle
Ich habe fast genau die gleiche Klasse geschrieben:
Vor dem Standard hat jeder Compiler es anders gemacht. Ich glaube, das alte Annotated Reference Manual für C ++ hat festgelegt, dass Provisorien am Ende des Bereichs bereinigt werden sollen, also haben einige Compiler dies getan. Noch 2003 stellte ich fest, dass das Verhalten im Forte C ++ - Compiler von Sun standardmäßig noch vorhanden war, sodass StringBuffer nicht funktionierte. Aber ich wäre erstaunt, wenn ein aktueller Compiler noch so kaputt wäre.
quelle