2014-04-06 4 views
5

eine Klasse Mit einer Referenzhalte ich den folgenden Code miserabel scheitern erwarten würde, aber es kompiliert:Warum kann die Klasse eine Referenz kopierbar halten?

#include <iostream> 

struct ReferenceHolder 
{ 
    std::string& str; 

    ReferenceHolder(std::string& str) 
    : str(str) 
    {} 
}; 

// Why does this compile? 
ReferenceHolder f() { 
    std::string str = "Hello"; 
    return ReferenceHolder(str); 
} 

int main() { 
    ReferenceHolder h = f(); 
    std::cout << "Should be garbage: " << h.str << '\n'; 
    return 0; 
} 

Compiler: g ++ 4.7.2 (mit -std = C++ 11)

Edit: Auch mit-fno-elide-Konstruktoren kompiliert es glücklich

+0

Offenbar wird es verschoben. Es kompiliert nicht, wenn Sie den Move-Konstruktor explizit löschen. – jrok

+0

@jrok Stimmt, aber soweit ich sehen kann, ist es kopierbar und beweglich. – dyp

+0

Interessanterweise würden Sie bei der Architektur der Mill CPU (Security Talk) einen Segmentierungsfehler erhalten. –

Antwort

7

Es gibt kein Problem mit der Kopierinitialisierung Ihrer Klasse, wie in Ihrem Beispiel: Die neue Referenz wird einfach initialisiert, um auf das gleiche Objekt wie das alte zu verweisen. Natürlich erhalten Sie dann undefiniertes Verhalten, wenn die Rückgabe der Funktion das Referenz-Dangling verlässt.

Die Referenz verhindert Standardinitialisierung und Kopierzuweisung; Die folgende kleine Änderung schlägt daher aus diesen Gründen fehl:

ReferenceHolder h; // ERROR: can't default-initialise the reference 
h = f();   // ERROR: can't reassign the reference. 
1

Dieser Code hat undefiniertes Verhalten, siehe the classic answer from Eric Lippert.

Die in der Referenz h wird in dem Rückgabewert von f() zur Referenz gebunden, das an die ReferenceHolder im Rück Expression gebunden ist, und so die h Referenzen str von f() außerhalb ihres Umfangs.

+0

Ich weiß das. Siehe: "Sollte Müll sein" –

+1

@ DieterLücking: Undefiniertes Verhalten bedeutet nicht "Müll", es bedeutet "alles". – Mankarse

+1

Mit anderen Worten kopiert der standardmäßige Kopierkonstruktor nur rekursiv Member (wie immer), und für Referenzen bedeutet dies nur, dass auf die Originaldaten verwiesen wird. Die einzige Sache, die Sie noch ansprechen müssen, ist Ihre Erwartung, dass der Code kläglich versagen wird und dass die Zeichenkette Müll enthält, wenn undefiniertes Verhalten keines dieser Dinge garantiert. – Mankarse

Verwandte Themen