Lokale Variable Bereichsfrage

8

Warum gibt der folgende Code "xxY" aus? Sollten lokale Variablen nicht im Rahmen der gesamten Funktion leben? Kann ich ein solches Verhalten verwenden oder wird dies in zukünftigen C ++ - Standards geändert?

Ich dachte, dass nach C ++ Standard 3.3.2 " Ein in einem Block deklarierter Name lokal für diesen Block ist. Sein potenzieller Umfang beginnt an seinem Deklarationspunkt und endet am Ende seiner deklarativen Region. "

%Vor%

Aufgrund der Antworten kann ich annehmen, dass MyClass(12345); der Ausdruck (und der Gültigkeitsbereich) ist. Das ist sinnvoll. Also erwarte ich, dass der folgende Code immer "xYx" ausgibt:

%Vor%

Und es ist erlaubt, einen solchen Ersatz zu machen:

%Vor%     
Kirill V. Lyadvinsky 07.09.2009, 10:37
quelle

4 Antworten

4

Sie haben den Standard korrekt zitiert. Lassen Sie mich betonen:

  

Ein Name deklariert in einem Block ist lokal für diesen Block. Sein potenzieller Geltungsbereich beginnt am Ort der Erklärung und endet am Ende seiner deklarativen Region.

Sie haben tatsächlich keinen Namen angegeben. Ihre Zeile

%Vor%

enthält nicht einmal eine Deklaration ! Es enthält einen Ausdruck, der eine Instanz von MyClass erstellt, den Ausdruck berechnet (aber in diesem speziellen Fall gibt es nichts zu berechnen), und wirft sein Ergebnis auf void und zerstört die dort erstellten Objekte.

Eine weniger verwirrende Sache würde wie

klingen %Vor% Du hast es viele Male gesehen und weißt, wie es funktioniert, nicht wahr?

    
Pavel Shved 07.09.2009, 10:50
quelle
16
___ answer1388695 ___

Sie erstellen ein Objekt tatsächlich, ohne es in seinem Umfang zu belassen. Daher wird es direkt nach der Erstellung zerstört. Daher das Verhalten, das Sie erleben.

Sie können nicht auf das erstellte Objekt zugreifen, also warum sollte der Compiler es beibehalten?

    
___ answer1389978 ___

Um Ihre anderen Fragen zu beantworten. Das folgende ist der Aufruf des Komma-Operators. Es erstellt %code% temporär, was den Aufruf seines Konstruktors beinhaltet. Dann wird der zweite Ausdruck %code% ausgewertet, der das Y ausgibt. Am Ende des vollständigen Ausdrucks wird dann das Temporäre zerstört, das seinen Destruktor aufrufen wird. Also waren deine Erwartungen richtig.

%Vor%

Damit das Folgende funktioniert, sollten Sie Klammern hinzufügen, da das Komma in Deklarationen eine vordefinierte Bedeutung hat. Es würde beginnen, eine Funktion %code% zu deklarieren, die ein %code% zurückgibt und keine Parameter annimmt, und würde das Objekt %code% zu %code% zuweisen. Wenn Sie Klammern verwenden, sagen Sie, dass die ganze Sache stattdessen ein einzelner Komma-Operator-Ausdruck ist.

%Vor%

Es sollte beachtet werden, dass die folgenden zwei Zeilen äquivalent sind. Der erste erstellt nicht ein temporäres unbenanntes Objekt mit %code% als Konstruktorargument, stattdessen sind die Klammern um den Namen redundant. Lass dich nicht von der Syntax verwirren.

%Vor%

Ich habe einen Missbrauch der Begriffe "Umfang" und "Lebensdauer" gesehen.

  • %code% ist der Ort, an dem Sie auf einen Namen verweisen können, ohne seinen Namen zu qualifizieren. Namen haben Geltungsbereiche, und Objekte erben den Geltungsbereich des Namens, der für ihre Definition verwendet wurde (daher sagt der Standard manchmal "lokales Objekt"). Ein temporäres Objekt hat keinen Gültigkeitsbereich, weil es keinen Namen hat. Ebenso hat ein Objekt, das von %code% erstellt wurde, keinen Gültigkeitsbereich. Bereich ist eine Kompilierzeiteigenschaft. Dieser Begriff wird im Standard häufig missbraucht, siehe diesen Fehlerbericht . also ist es ziemlich verwirrend, eine echte Bedeutung zu finden.

  • %code% ist eine Laufzeiteigenschaft. Es bedeutet, wenn das Objekt eingerichtet und einsatzbereit ist. Bei einem Objekt vom Typ class beginnt die Lebensdauer, wenn der Konstruktor die Ausführung beendet, und endet, wenn der Destruktor mit der Ausführung beginnt. Die Lebenszeit wird oft mit dem Umfang verwechselt, obwohl diese beiden Dinge völlig unterschiedlich sind.

    Die Lebensdauer von Provisorien ist genau definiert. Die meisten von ihnen beenden die Lebensdauer nach der Auswertung des vollständigen Ausdrucks, in dem sie enthalten sind (wie der Komma-Operator von oben oder ein Zuweisungsausdruck). Provisorien können an Const-Referenzen gebunden werden, die ihre Lebensdauer verlängern. Objekte, die in Ausnahmen ausgelöst werden, sind ebenfalls temporär und ihre Lebensdauer endet, wenn für sie kein Handler mehr existiert.

___ tag123c ___ C ++ ist eine universelle Programmiersprache. Es wurde ursprünglich als Erweiterung von C entworfen und behält eine ähnliche Syntax, ist aber jetzt eine völlig andere Sprache. Verwenden Sie dieses Tag für Fragen zu Code, der mit einem C ++ - Compiler kompiliert werden soll. ___ tag123scope ___ Scope ist ein einschließender Kontext, in dem Werte und Ausdrücke verknüpft sind. Verwenden Sie dieses Tag für Fragen zu verschiedenen Arten von Bereichen sowie für Fragen, deren Umfang unklar sein könnte. ___ qstnhdr ___ Lokale Variable Bereichsfrage ___ tag123raii ___ Die Initialisierung der Ressourcenerfassung (RAII) ist ein gängiges Idiom in C ++ zur Verwaltung der Lebensdauer von Ressourcen, einschließlich Speicherzuordnungen, Dateihandles oder Datenbankverbindungen. Kurz gesagt, jede Ressource sollte in eine besitzende Klasse eingeschlossen sein, deren Lebensdauer die Lebensdauer der Ressource steuert. ___ qstntxt ___

Warum gibt der folgende Code "xxY" aus? Sollten lokale Variablen nicht im Rahmen der gesamten Funktion leben? Kann ich ein solches Verhalten verwenden oder wird dies in zukünftigen C ++ - Standards geändert?

Ich dachte, dass nach C ++ Standard 3.3.2 " Ein in einem Block deklarierter Name lokal für diesen Block ist. Sein potenzieller Umfang beginnt an seinem Deklarationspunkt und endet am Ende seiner deklarativen Region. "

%Vor%

Aufgrund der Antworten kann ich annehmen, dass %code% der Ausdruck (und der Gültigkeitsbereich) ist. Das ist sinnvoll. Also erwarte ich, dass der folgende Code immer "xYx" ausgibt:

%Vor%

Und es ist erlaubt, einen solchen Ersatz zu machen:

%Vor%     
___ antwort1388700 ___

Das in Ihrem

erstellte Objekt %Vor%

ist ein temporäres Objekt, das in diesem Ausdruck nur lebendig ist ;

%Vor%

ist ein Objekt, das für den gesamten Block aktiv ist.

    
___ answer1388752 ___

Sie haben den Standard korrekt zitiert. Lassen Sie mich betonen:

  

Ein Name deklariert in einem Block ist lokal für diesen Block. Sein potenzieller Geltungsbereich beginnt am Ort der Erklärung und endet am Ende seiner deklarativen Region.

Sie haben tatsächlich keinen Namen angegeben. Ihre Zeile

%Vor%

enthält nicht einmal eine Deklaration ! Es enthält einen Ausdruck, der eine Instanz von MyClass erstellt, den Ausdruck berechnet (aber in diesem speziellen Fall gibt es nichts zu berechnen), und wirft sein Ergebnis auf %code% und zerstört die dort erstellten Objekte.

Eine weniger verwirrende Sache würde wie

klingen %Vor% Du hast es viele Male gesehen und weißt, wie es funktioniert, nicht wahr?

    
___
JesperE 07.09.2009 10:40
quelle
8

Sie erstellen ein Objekt tatsächlich, ohne es in seinem Umfang zu belassen. Daher wird es direkt nach der Erstellung zerstört. Daher das Verhalten, das Sie erleben.

Sie können nicht auf das erstellte Objekt zugreifen, also warum sollte der Compiler es beibehalten?

    
Philippe Leybaert 07.09.2009 10:39
quelle
5

Um Ihre anderen Fragen zu beantworten. Das folgende ist der Aufruf des Komma-Operators. Es erstellt MyClass temporär, was den Aufruf seines Konstruktors beinhaltet. Dann wird der zweite Ausdruck cout << "Y" << endl ausgewertet, der das Y ausgibt. Am Ende des vollständigen Ausdrucks wird dann das Temporäre zerstört, das seinen Destruktor aufrufen wird. Also waren deine Erwartungen richtig.

%Vor%

Damit das Folgende funktioniert, sollten Sie Klammern hinzufügen, da das Komma in Deklarationen eine vordefinierte Bedeutung hat. Es würde beginnen, eine Funktion some_func zu deklarieren, die ein int zurückgibt und keine Parameter annimmt, und würde das Objekt scoped_lock zu x zuweisen. Wenn Sie Klammern verwenden, sagen Sie, dass die ganze Sache stattdessen ein einzelner Komma-Operator-Ausdruck ist.

%Vor%

Es sollte beachtet werden, dass die folgenden zwei Zeilen äquivalent sind. Der erste erstellt nicht ein temporäres unbenanntes Objekt mit my_mutex als Konstruktorargument, stattdessen sind die Klammern um den Namen redundant. Lass dich nicht von der Syntax verwirren.

%Vor%

Ich habe einen Missbrauch der Begriffe "Umfang" und "Lebensdauer" gesehen.

  • Scope ist der Ort, an dem Sie auf einen Namen verweisen können, ohne seinen Namen zu qualifizieren. Namen haben Geltungsbereiche, und Objekte erben den Geltungsbereich des Namens, der für ihre Definition verwendet wurde (daher sagt der Standard manchmal "lokales Objekt"). Ein temporäres Objekt hat keinen Gültigkeitsbereich, weil es keinen Namen hat. Ebenso hat ein Objekt, das von new erstellt wurde, keinen Gültigkeitsbereich. Bereich ist eine Kompilierzeiteigenschaft. Dieser Begriff wird im Standard häufig missbraucht, siehe diesen Fehlerbericht . also ist es ziemlich verwirrend, eine echte Bedeutung zu finden.

  • Lifetime ist eine Laufzeiteigenschaft. Es bedeutet, wenn das Objekt eingerichtet und einsatzbereit ist. Bei einem Objekt vom Typ class beginnt die Lebensdauer, wenn der Konstruktor die Ausführung beendet, und endet, wenn der Destruktor mit der Ausführung beginnt. Die Lebenszeit wird oft mit dem Umfang verwechselt, obwohl diese beiden Dinge völlig unterschiedlich sind.

    Die Lebensdauer von Provisorien ist genau definiert. Die meisten von ihnen beenden die Lebensdauer nach der Auswertung des vollständigen Ausdrucks, in dem sie enthalten sind (wie der Komma-Operator von oben oder ein Zuweisungsausdruck). Provisorien können an Const-Referenzen gebunden werden, die ihre Lebensdauer verlängern. Objekte, die in Ausnahmen ausgelöst werden, sind ebenfalls temporär und ihre Lebensdauer endet, wenn für sie kein Handler mehr existiert.

Johannes Schaub - litb 07.09.2009 15:54
quelle

Tags und Links