2016-06-22 8 views
9

Betrachten Sie diesen Code:Beträgt die Bindung einer Referenz tatsächlich den Operanden?

int& x=*new int; 

Does RHS der Zuordnung tatsächlich dereferenzieren der neu erstellten Zeiger aufgrund Lesen nicht initialisierten Variablen zu UB führen? Oder kann dies legitim verwendet werden, um später einen Wert wie x=5; zuzuweisen?

+2

Dies ist legitimer Code und sicher, solange Sie 'x' später mit einem Wert initialisieren, anstatt die nicht initialisierte Variable für einen bestimmten Zweck zu verwenden. Bessere Sache wäre 'int & x = * new int()', die es auch auf Nullwert initialisiert. Und natürlich müssen Sie den zugewiesenen Speicher löschen. – Arunmu

+4

Ich glaube nicht, dass es anders ist als 'int y; int & x = y; ', was übrigens passiert, wenn du' int y; std :: cin >> y; ' – dyp

Antwort

6

Soweit ich sagen kann, nichts von dem, was Sie getan haben, beinhaltet undefined Verhalten.

Es erzeugt jedoch sofort das Risiko eines Speicherlecks. Es kann schnell aufgelöst werden (da &x auf die Adresse des durchgesickerten Speichers aufgelöst werden würde und daher gelöscht werden kann), aber wenn Sie den Gültigkeitsbereich verlassen würden, hätten Sie keine Möglichkeit, diesen Zeiger abzurufen.

Edit: auf den Punkt, wenn Sie

int& x=*new int; 
x = 5; 

std::cout << x << std::endl; 

std::cin >> x; 

std::cout << x << std::endl; 

Der Code schreiben, so würde sich verhalten, als ob Sie einfach x als int x; erklärt hatten, mit der Ausnahme, dass der Zeiger auch baumelnden würde links nach dem Programmbereich verlassen .

Sie würden ein undefiniertes Verhalten erreichen, wenn Sie versuchen würden, die nicht initialisierte Variable vor dem Zuweisen eines Werts zu lesen, aber das wäre nicht falsch, wenn x dem Stack zugewiesen wäre.

+1

@BenjaminLindley Überarbeitete die Sprache, um zu sagen:" Erschaffe ein * Risiko * eines Speicherlecks ". Und der Grund, warum ich es in erster Linie als Speicherleck bezeichne, liegt darin, dass der Code selbst keinen vom Benutzer sichtbaren Zeiger auf den Speicher enthält. – Xirema

0

Ich würde nicht empfehlen, dies zu tun. Es ist gefährlich für mich, dynamischen Speicher mit einer statischen Variablen zu aliasieren. Betrachten Sie den folgenden Code

#include <iostream> 

int* dynamicAlloc() { 
    int& x = *new int; 
    std::cout << "Inside dynamicAlloc: " << x << std::endl; 
    std::cout << "Modified: " << (x = 1) << std::endl; 
    return &x; 
} 

int main() { 
    int *dall = dynamicAlloc();; 

    std::cout << "dall (address): " << dall << std::endl; 
    std::cout << "dall -> " << *dall << std::endl; // Memory not cleaned 

    delete dall; // Don't forget to delete 

    return 0; 
} 

I Ausgabe wie folgt erhalten:

Inside dynamicAlloc: -842150451 
Modified: 1 
dall (address): 00F642A0 
dall -> 1 

Hinweis, wie dereferencing dall nicht in einem segfault führt. Es wurde nicht freigegeben, wenn x außerhalb des Gültigkeitsbereichs fiel. Andernfalls wäre wahrscheinlich ein Segfault aufgetreten.

Fazit:

int& x macht x Alias ​​für den Speicher dynamisch zugewiesen. Sie können diesen Speicher legitim ändern, aber er wird nicht aufgeräumt, da er automatisch aus dem Bereich fällt, was leicht zu Speicherlecks führen kann.

+0

Ich verstehe das nicht. Natürlich können Sie einen Zeiger nicht verwenden, nachdem er gelöscht wurde. Das einzige Risiko für die OPs besteht darin, dass der Speicher, wenn er nicht richtig gehandhabt wird, undicht werden könnte. – NathanOliver

+0

Der Hauptzweck bestand darin, zu demonstrieren, dass die Adresse nicht freigegeben wird, nachdem 'x' in' test() 'außerhalb des Bereichs liegt. Sie könnten später 'x' löschen, wenn Sie Dinge richtig verwalten, aber es ist nicht intuitiv. Ich werde darüber nachdenken, wie ich es nach der Arbeit umschreiben kann. – Assimilater

+0

Hoffentlich ist der Wortlaut jetzt etwas besser – Assimilater