Forum: PC-Programmierung Unterschied zwischen int i; in while und vor while


von Student (Gast)


Lesenswert?

Hallo,

ich habe einen c-Quellcode gefunden, da steht das:
1
...
2
   while (!exit) {
3
       int i=0;
4
       ...
5
   }

Ist das denn ok, wenn man eine Variable in einer while-Schleife immer 
wieder neu erstellt? Ich habe das noch nie gesehen, ich kannte das 
bisher nur so:


1
int i;
2
...
3
   while (!exit) {
4
       i=0;
5
       ...
6
   }

Also, ich habe es probiert - es funktioniert beides. Aber dennoch finde 
ich das erste etwas seltsam.

: Verschoben durch Moderator
von Bastler (Gast)


Lesenswert?

Das ist keine Scriptsprache sondern C. Die Variable wird natürlich nur 
einmal erstellt (ein Register dafür reserviert soweit möglich oder auf 
dem Stack angelegt). Sie wird in jedem Durchlauf auf 0 gesetzt.

von Peter II (Gast)


Lesenswert?

Bastler schrieb:
> Das ist keine Scriptsprache sondern C. Die Variable wird natürlich nur
> einmal erstellt (ein Register dafür reserviert soweit möglich oder auf
> dem Stack angelegt). Sie wird in jedem Durchlauf auf 0 gesetzt.

nicht wirklich. Da man es mit jedem Datentype machen kann (also auch 
komplexe Objekte) wird das Objekt jedes mal erstellt und der Konstructor 
aufgerufen.

das bei int der Optimierer etwas optimieren kann ja klar.

von (prx) A. K. (prx)


Lesenswert?

Student schrieb:
> Also, ich habe es probiert - es funktioniert beides. Aber dennoch finde
> ich das erste etwas seltsam.

Völlig normal und schon in K&R C drin. Variablen innerhalb der Blöcke zu 
deklarieren macht sowohl dem Compiler als auch dem Programmierer klar, 
dass sie nur dort gebraucht werden. Heutige Compiler kriegen das auch 
selber spitz, damalige konnten von dieser Programmiertechnik 
profitieren.

von Hans (Gast)


Lesenswert?

Im ersten Fall ist die Variable nur innerhalb des Blocks gültig, d.h. 
innerhalb der geschweiften Klammern. Du kannst also nach der Schleife 
nicht mehr darauf zugreifen.

Im anderen Fall ist die Variable außerhalb der Schleife definiert und 
kann auch danach noch verwendet werden.

Allgemein sollte man Variablen immer so weit "innen" wie möglich 
definieren, also mit möglichst kurzer Sichtbarkeit. Falls sie also nur 
innerhalb der Schleife gebraucht wird, sollte sie auch nur dort gültig 
sein. Das macht den Code übersichtlicher.

von Ulrich F. (Gast)


Lesenswert?

Bei dem Beispiel, würde ich sagen:
Wenn man i außerhalb der Schleife noch braucht, dann muss man sie 
außerhalb definieren.
Ansonsten ist es immer gut, Variablem möglichst zu verbergen.

Die erste Variante ist also gut, die zweite eher böse.

von Student (Gast)


Lesenswert?

A. K. schrieb:
> K&R C drin

Das war mir noch nie aufgefallen, dass es das damals schon so gemacht 
wurde und ich programmiere schon seit einem vierteljahrhundert in C - 
und siehe, ich lerne immer wieder was neues dazu - krass.

von (prx) A. K. (prx)


Lesenswert?

Student schrieb:
> ich programmiere schon seit einem vierteljahrhundert in C

Wunderkind oder Langzeitstudent?

von Hans (Gast)


Lesenswert?

Peter II schrieb:
> Bastler schrieb:
>> Das ist keine Scriptsprache sondern C. Die Variable wird natürlich nur
>> einmal erstellt (ein Register dafür reserviert soweit möglich oder auf
>> dem Stack angelegt). Sie wird in jedem Durchlauf auf 0 gesetzt.
>
> nicht wirklich. Da man es mit jedem Datentype machen kann (also auch
> komplexe Objekte) wird das Objekt jedes mal erstellt und der Konstructor
> aufgerufen.
>
> das bei int der Optimierer etwas optimieren kann ja klar.

Man sollte aber auch dazu sagen, dass das Objekt am Ende des Blocks, 
sprich mit der schließenden Klammer, wieder zerstört wird. Der dabei 
frei werdende Speicher auf dem Stack wird im nächsten Durchlauf 
wiederverwendet.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Peter II schrieb:
> (also auch komplexe Objekte) wird das Objekt jedes mal erstellt und der
> Konstructor aufgerufen.

Falsch. C kennt weder Objekte noch Konstruktoren. Für C++ wäre Deine 
Behauptung jedoch zutreffend.

von Markus (Gast)


Lesenswert?

Student schrieb:
> Aber dennoch finde ich das erste etwas seltsam.
Es gibt Leute, die propagieren, alle Variablen, die eine Funktion 
braucht, am Funktionsanfang zu deklarieren.
Und es gibt Leute, die propagieren, eine Variable erst dort zu 
deklarieren, wo sie auch gebraucht wird.
Bei letzterem braucht man sich um Performance oder Stackverbrauch keine 
Gedanken zu machen, wenn z.B. eine Funktion mehrere Schleifen enthält 
und diese jeweils immer wieder dieselben Variablen deklarieren. Der 
Conpiler optimiert das schon richtig.
Eine Funktion mit mehrerer Schleifen hat aber eh schon ein Problem: 
unübersichtlich -> jeweils in eine eigene Funktion. Kann man dann ja 
selber inlinen, wenn man meint, schlauer als der Compiler zu sein.

von Student (Gast)


Lesenswert?

A. K. schrieb:
> Wunderkind oder Langzeitstudent?

Beides. Ich hab das Studium Generale gemacht.

von Klaus (Gast)


Lesenswert?

Hans schrieb:
> Allgemein sollte man Variablen immer so weit "innen" wie möglich
> definieren, also mit möglichst kurzer Sichtbarkeit. Falls sie also nur
> innerhalb der Schleife gebraucht wird, sollte sie auch nur dort gültig
> sein. Das macht den Code übersichtlicher.

Das find ich garnicht. Man muß, beim Lesen des Codes, zusätzlich zum 
Variablennamen immer noch den Scope im Kopf mitführen.

Ist "i" immer noch das gleiche i wie eine Seite vorher oder hat da 
jemand nur das int vergessen oder hab ichs überlesen? Also nochmal 
zurückscrollen...

MfG Klaus

von Tom (Gast)


Lesenswert?

Klaus schrieb:
> Ist "i" immer noch das gleiche i wie eine Seite vorher

Dann ist die Funktion viiiiiiiel zu lang und komplex.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Tom schrieb:
>> Ist "i" immer noch das gleiche i wie eine Seite vorher
>
> Dann ist die Funktion viiiiiiiel zu lang und komplex.

Oder der Monitor zu klein.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Klaus schrieb:
> Ist "i" immer noch das gleiche i wie eine Seite vorher oder hat da
> jemand nur das int vergessen oder hab ichs überlesen? Also nochmal
> zurückscrollen..

Ist es nicht eher andersherum?

Um zu sehen, was es mit einer Variable auf sich hat, muss man maximal
bis zur ihrer Deklaration zurückscrollen. Je näher Deklaration und
Verwendung beieinander liegen, umso besser also.

Dennoch benutze ich solche eingeschränkten Scopes recht selten, weiß
aber nicht warum. Da muss ich vielleicht mal in mich gehen ;-)

von Klaus (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Oder der Monitor zu klein.

Das ist meiner sicher, aber 30 bis 50 Zeilen aktiver Code einer Funktion 
zusammen mit einer übersichtlichen Formatierung sowie diversen anderen 
Fenstern und Toolbars übersteigen leicht auch größere Monitore. Und die 
Komplexität einer Funktion mache ich nicht an der Länge, sondern an der 
Komplexität fest.

Ich definiere lokale Variable immer am Anfang und lass mir vom Compiler 
helfen, wenn ich eine übersehen habe oder eine nicht mehr brauche.

MfG Klaus

von Stefan F. (Gast)


Lesenswert?

In C werden Variablen nicht erstellt, sondern benutzt. Für jede Variable 
wird VOR dem Eintritt in den jeweiligen Block Speicher belegt.
1
int a;
2
3
main()
4
{
5
  int b;
6
7
  while (1)
8
  {
9
     int c;
10
  }
11
}

Für a wird Speicher belegt, bevor die main() Funktion aufgerufen wird.
Für b wird ebenfalls Speicher belegt, bevor die main() Funktion 
ausgeführt wird.

Für c wird Speicher belegt, bevor die while Schleife ausgeführt wird. 
Soweit ich weiss, darf der Compiler sich aussuchen, wann genau dieses 
VOR ist.

So oder so gibt es alle drei Variablen nur einmal. Die Variable c 
entspricht einem Speicherplatz. Sie wird nicht bei jeden 
Schleifendurchlauf neu erstellt oder initialisiert. Die Deklaration 
innerhalb der Schleife sagt nur aus, dass sie außerhalb der Schleife 
unbekannt ist.

Ich vermute, dass ein Verschieben unter die Variable b letztendlich 
exakt den gleichen Maschinencode erzeugt. Denn der Prozessor 
unterscheidet nicht zwischen Gültigkeitsbereichen.

von (prx) A. K. (prx)


Lesenswert?

Interessanter ist eher dieser Fall:
1
{
2
   int x;
3
   ...
4
}
5
{
6
   long y;
7
   ...
8
}
9
{
10
   unsigned z;
11
   ...
12
}
denn hier kann für alle 3 Variablen der gleiche Speicher bzw. das 
gleiche Register verwendet werden. Freilich war das früher wichtiger als 
heute, denn Compiler wie GCC kriegen selber raus, in welchen 
Codebereichen eine Variable verwendet wird und in welchen nicht. Früher 
war es üblich, dem Compiler mit "register int x;" einen entsprechenden 
Tipp zu geben - da konnte solcher Code entscheidend sein.

Stefan U. schrieb:
> Für jede Variable
> wird VOR dem Eintritt in den jeweiligen Block Speicher belegt.

Im real erzeugte Code geschieht das oft für alle zusammen an Anfang/Ende 
der Funktion, also was Platz auf dem Stack und zu sichernde Register 
angeht. Weil sonst unnötiger Code produziert wird.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

1
    int loop=0;
2
    while (loop<3)
3
    {
4
        int counter;
5
        if (loop==0)
6
        {
7
            counter=0;
8
        }
9
        counter++;
10
        printf("Loop %d, counter %d\n",loop,counter);
11
        loop++;
12
    }
Erzeugt (in C und C++) die Ausgabe:

Loop 0, counter 1
Loop 1, counter 2
Loop 2, counter 3

Soweit nicht überraschend. Jedoch verhält sich Java anders!:

Loop 0 , counter 1
Loop 1 , counter 1
Loop 2 , counter 1

Interessanter finde ich, was bei diesem Code passiert:
1
    int loop=0;
2
    while (loop<3)
3
    {
4
        int counter=0;
5
        counter++;
6
        printf("Loop %d, counter %d\n",loop,counter);
7
        loop++;
8
    }
9
    return 0;
10
11
Erzeugt (in C, C++ und Java) die Ausgabe: 
12
Loop 0, counter 1
13
Loop 1, counter 1
14
Loop 2, counter 1
Hier wird die Variable bei jedem Schleifendurchlauf initialisiert, 
obwohl sie nur einmal (vor Eintritt in die Schleife) erzeugt wurde.

Ich liebe solche Corner-Cases :-)

von (prx) A. K. (prx)


Lesenswert?

Stefan U. schrieb:
> Interessanter finde ich, was bei diesem Code passiert:

Wieso? Ist doch streng nach Vorschrift.

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Stefan U. schrieb:
> Soweit nicht überraschend
1
int loop=0;
2
    while (loop<3)
3
    {
4
        int counter;
5
        if (loop==0)
6
        {
7
            counter=0;
8
        }
9
        counter++;
10
        printf("Loop %d, counter %d\n",loop,counter);
11
        loop++;
12
    }
doch schon überraschend, und sogar fehlerhaft.

Man sollte nie eine nicht initialisierte Variable verwenden und hoffen 
das das richte drin steht.

von Michael (Gast)


Lesenswert?

Stefan U. schrieb:
> Interessanter finde ich, was bei diesem Code passiert:
>
>[...]
>
> Hier wird die Variable bei jedem Schleifendurchlauf initialisiert,
> obwohl sie nur einmal (vor Eintritt in die Schleife) erzeugt wurde.
>
> Ich liebe solche Corner-Cases :-)

Nach der Öffnenden Klammer der while ist doch nicht "vor Eintritt in die 
Schleife", sondern genau am Anfang dieser... Das Ergebnis ist doch 
plausibel, die Erzeugung (bzw. Allokierung...) und Initialisierung 
erfolgt eben wie jedes andere Statement innerhalb der Schleife mit jedem 
Durchlauf erneut.

von Stefan F. (Gast)


Lesenswert?

> Man sollte nie eine nicht initialisierte Variable verwende

Sie ist doch initialisiert! Beim ersten Schleifendurchlauf initialisiere 
ich sie mit 0. Erst danach wird sie (beim incrementieren) zum ersten mal 
gelesen.

von Stefan F. (Gast)


Lesenswert?

> die Erzeugung (bzw. Allokierung...) und Initialisierung
> erfolgt eben wie jedes andere Statement innerhalb der Schleife mit
> jedem Durchlauf erneut.

Bei C/C++ eben nicht! Darum geht es ja in diesem Thread. Die Variable 
wird nicht innerhalb der Schleife erezugt, sondern vorher.

Deine Aussage trifft wohl auf Java zu, aber nicht auf C/C++. Das beweist 
mein erster Test.

von Peter II (Gast)


Lesenswert?

Stefan U. schrieb:
> Sie ist doch initialisiert! Beim ersten Schleifendurchlauf initialisiere
> ich sie mit 0. Erst danach wird sie (beim incrementieren) zum ersten mal
> gelesen.

das sagst du. Ich behaupte die variabel ist in jedem Durchlauf "neu". 
Damit nicht initialisiert.

Nur weil sie zufällig immer an der gleichen Stelle im Speicher seht, 
kann man sich doch nicht darauf verlassen. Was ist wenn die schleife 
aufgerollt wird?
[c]
    {
        int counter;
        counter=0;
        counter++;
        printf("Loop %d, counter %d\n",loop,counter);
    }

    {
        int counter;
        counter++;
        printf("Loop %d, counter %d\n",loop,counter);
    }

    {
        int counter;
        counter++;
        printf("Loop %d, counter %d\n",loop,counter);
    }
[c]

dann kommt das raus.

von (prx) A. K. (prx)


Lesenswert?

Michael schrieb:
> die Erzeugung (bzw. Allokierung...) und Initialisierung
> erfolgt eben wie jedes andere Statement innerhalb der Schleife mit jedem
> Durchlauf erneut.

Die Allokation lokaler Variablen darf wie hier zu sehen auch ausserhalb 
des Gültigkeitsbereichs stattfinden. Die Initialisierung ist ein davon 
unabhängiges Thema, das hat nichts miteinander zu tun.

von Axel S. (a-za-z0-9)


Lesenswert?

Markus schrieb:
> Es gibt Leute, die propagieren, alle Variablen, die eine Funktion
> braucht, am Funktionsanfang zu deklarieren.
> Und es gibt Leute, die propagieren, eine Variable erst dort zu
> deklarieren, wo sie auch gebraucht wird.

Das hat wenig mit propagieren zu tun sondern eher damit, daß frühe C 
Compiler verlangt haben, daß lokale Variablen am Anfang des Blocks 
deklariert werden. Erst C99 (der C-Standard von 1999) erlaubt offiziell, 
daß man Variablen an beliebiger Stelle eines Blocks deklarieren kann:

https://de.wikipedia.org/wiki/Varianten_der_Programmiersprache_C#Neuerungen_von_C99

Lesbarer ist es allemal, wenn man Variablen erst dann deklariert wenn 
man sie braucht.

von Karl H. (kbuchegg)


Lesenswert?

Stefan U. schrieb:
>> die Erzeugung (bzw. Allokierung...) und Initialisierung
>> erfolgt eben wie jedes andere Statement innerhalb der Schleife mit
>> jedem Durchlauf erneut.
>
> Bei C/C++ eben nicht!


Doch wird sie.
Stefan du solltest noch mal deine Literatur studieren. Du hast da ein 
paar sehr gefaehrliche und sehr falsche Fehlansichten ueber C.

Die Variable kommt konzeptionell bei jedem Schleifendurchlauf erneut zur 
Welt und wird am Ende jedes Schleifendurchlaufs zerstoert. Dass ein 
Compiler das auch unter Umstaenden abaendern kann, wenn *es im Ergebnis 
auf das gleiche rauskommt* ist ein davon losgeloestes Thema!

Da eine lokale Variable ohne Initialisierung irgendeinen Wert hat, ist 
es auch ok, wenn sie zufaellig den Wert von vorher hat. Das kann so 
sein, das muss aber nicht so sein. Irgendein Wert ist nun mal irgendener

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Ich versuche gerade, die Spezifikation dazu zu finden.

Für eine Variable, die innerhalb eine Schleife deklariert ist: Ist die 
Variable nur für einen oder für alle Wiederholungen der Schleife gültig?

Bei meinem Test war sie für alle Wiederholungen gültig. Peter II meint, 
dass dies nur Zufall war.

Gefunden habe ich das: 
http://eli-project.sourceforge.net/c_html/c.html#s8.3

An Environment value for all identifiers in a block scope is therefore 
created either at the beginning of the block... In either case, the 
value is discarded at the end of the block.

Nur, was genau ist "the end of the block"? Wenn eine While Schleife 
wiederholt wird, trifft die Auführung dabei wiederholt auf das Ende des 
Blockes, oder erst danach, wenn die Schleife verlassen wird?

Woanders in der Spezifikation habe ich das gefunden:

RULE: iteration_statement ::= 'while' '(' Expression ')' statement

Wenn die while Schleife EIN Statement wiederholt ausführt und dieses 
Statement auch ein ganzer Block sein darf, dann verstehe ich es so, dass 
der Block mehmals ausgeführt wird. Also wird er merhmals begonnen und 
mehrmals beendet. Womit ich nun Peter II zustimme.

Ist meine Schlussfolgerung richtig?

von Stefan F. (Gast)


Lesenswert?

Bastler Aussage
> Die Variable wird natürlich nur einmal erstellt

konnte ich durch meinen Test bestätigen, aber wohl nur wegen eines 
Zufalls. Diese Aussage ist wohl doch falsch.

Meine Aussage "Für c wird Speicher belegt, bevor die while Schleife 
ausgeführt wird." war ebenso falsch.

von Karl H. (kbuchegg)


Lesenswert?

Stefan U. schrieb:
> Ich versuche gerade, die Spezifikation dazu zu finden.
>
> Für eine Variable, die innerhalb eine Schleife deklariert ist: Ist die
> Variable nur für einen oder für alle Wiederholungen der Schleife gültig?

Fuer einen Durchlauf.
Der Block wird jedesmal neu betreten und verlassen

von Karl H. (kbuchegg)


Lesenswert?

Stefan U. schrieb:
> Ich versuche gerade, die Spezifikation dazu zu finden.
>
> Für eine Variable, die innerhalb eine Schleife deklariert ist: Ist die
> Variable nur für einen oder für alle Wiederholungen der Schleife gültig?
>
> Bei meinem Test war sie für alle Wiederholungen gültig. Peter II meint,
> dass dies nur Zufall war.
>
> Gefunden habe ich das:
> http://eli-project.sourceforge.net/c_html/c.html#s8.3
>
> An Environment value for all identifiers in a block scope is therefore
> created either at the beginning of the block... In either case, the
> value is discarded at the end of the block.
>
> Nur, was genau ist "the end of the block"? Wenn eine While Schleife
> wiederholt wird

Der springende Punkt ist, dass die while Schleife (alle Compound 
Statements) nichts von einem Block weiss! Ein while wiederholt ein 
Statement!
Das dieses Statement zufaellig dergestalt ist, dass es aus Blockklammern 
und mehreren dadurch gruppierten Statements besteht, interessiert das 
while nicht. Die { } Klammern gehoeren NICHT zum while, sondern bilden 
das Statement.

Deine letzte Schlussfolgerung war, soweit ich das sehen kann, richtig

von (prx) A. K. (prx)


Lesenswert?

Stefan U. schrieb:
> Meine Aussage "Für c wird Speicher belegt, bevor die while Schleife
> ausgeführt wird." war ebenso falsch.

Dies kann der Fall sein, muss aber nicht. Entscheidend ist das:

Karl H. schrieb:
> Die Variable kommt konzeptionell bei jedem Schleifendurchlauf erneut zur
> Welt und wird am Ende jedes Schleifendurchlaufs zerstoert. Dass ein
> Compiler das auch unter Umstaenden abaendern kann, wenn *es im Ergebnis
> auf das gleiche rauskommt* ist ein davon losgeloestes Thema!

Der Standard beschreibt das Normverhalten anhand einer Pseudomaschine 
(abstract virtual machine). Gleichzeitig gilt aber auch die "as if 
rule", d.h. solange das Verhalten der erzeugten Codes auf der realen 
Maschine innerhalb der Spezifikation zu diesem Normverhalten passt, hat 
der Compiler die Freiheit, es anders zu implementieren als diese 
Pseudomaschine nahelegt.

In
1
  { int x = 0;
2
    ...
3
  }
ist zweierlei drin: Die Allokation und die Initialisierung.

Die Initialisierung muss an dieser Stelle stattfinden, sonst stimmt das 
Verhalten nicht.

Die Allokation hingegen darf an dieser Stelle stattfinden, darf aber 
auch vorher stattfinden, weil das am Verhalten im Rahmen der C 
Spezifikation nichts ändert. Die Adresse oder die Registernummer darf 
bei jedem Durchlauf unterschiedlich sein, darf aber auch gleich sein. 
Beim oben aufgeführten loop unrolling wird die Variable oft durch einen 
Satz von verschiedenen Registern rotieren.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Um die Sache noch etwas komplizierter zu gestalten:

Die tatsächliche Allokation von Variablen wird sich bei stark 
optimierenden Compilern nicht selten auch innerhalb der Gültigkeit der 
Variablen ändern. Oder auch vollständig entfallen.

Eine Variable, die am Anfang einer Funktion definiert wird, wird nicht 
notwendigerweise an dieser Stelle alloziert. Das wird sie bei Registern 
oft erst an jener Stelle, an der sie tatsächlich zum ersten Mal 
verwendet wird.

Wobei man das nicht lexikalisch genau nehmen sollte, denn in "int x=0;" 
wird der Compiler vielleicht erst einmal überhaupt nichts erzeugen, 
sondern sich nur merken, dass es ein x mit Wert 0 gibt. Erst dort, wo 
das x verwendet wird, wird er dann vielleicht ein grad freies Register 
mit 0 belegen, oder vielleicht auch direkt den Wert 0 dort einsetzen, wo 
x steht. Mit der Folge, dass vielleicht nie irgendein Platz für x 
alloziert wird. [Dies ist ein Beispiel für linearen Code, bei Schleifen 
sieht das wieder anders aus]

Zudem kann sich die Allokation auch mittendrin ändern, um beispielsweise 
ein anderweitig dringender benötigtes Register frei zu bekommen. Bloss 
um dann später vielleicht in einem anderen Register zu landen, oder auch 
im Speicher.

Folgen hat das für Debugging mit eingeschalteter Optimierung: Compiler 
und Debugger haben dann recht viel Mühe, die notwendige Information so 
zu erzeugen und auszuwerten, das der Debugger stets an der richtigen 
Stelle nachsieht.

Einmal mehr die "as if rule": Der Compiler muss nur dafür sorgen, dass 
das spezifizierte Verhalten eingehalten wird. Der ist jedoch nicht 
gezwungen, den Maschinencode exakt in der Reihenfolge des Quellcodes zu 
erzeugen.

: Bearbeitet durch User
von Hans (Gast)


Lesenswert?

Yalu X. schrieb:
> Klaus schrieb:
>> Ist "i" immer noch das gleiche i wie eine Seite vorher oder hat da
>> jemand nur das int vergessen oder hab ichs überlesen? Also nochmal
>> zurückscrollen..
>
> Ist es nicht eher andersherum?
>
> Um zu sehen, was es mit einer Variable auf sich hat, muss man maximal
> bis zur ihrer Deklaration zurückscrollen. Je näher Deklaration und
> Verwendung beieinander liegen, umso besser also.
>
> Dennoch benutze ich solche eingeschränkten Scopes recht selten, weiß
> aber nicht warum. Da muss ich vielleicht mal in mich gehen ;-)

Vielleicht solltest Du mehr C++ programmieren. ;-)

Dort entscheiden die Scopes, wann die Konstruktoren und Destruktoren 
aufgerufen werden. Wenn man sämtliche Objekte gleich zur Beginn der 
Funktion anlegt (und implizit erst am Ende der Funktion zerstört) kann 
das deutlich Performance kosten. Beispielsweise, wenn man ein teuer zu 
konstruierendes Objekt in manchen Zweigen gar nicht braucht. Oder einen 
stark gewachsenen Container mit seinem Heap-Speicher unnötig spät 
freigibt und deshalb ingesamt mehr Speicher benötigt.

Dabei geht es nicht nur um Speicher, sondern ggf. auch andere Ressourcen 
(Stichwort RAII). Ein gutes Beispiel sind Lock-Guards, also Objekte, die 
ein Mutex im Konstruktor belegen und im Destruktor wieder freigebenen. 
Die möchte man möglichst eng um die Stelle legen, die auf die zu 
schützenden Objekte zugreift, und nicht die komplette Funktion über 
halten. Das kann einen massiven Unterschied in der 
Multithreading-Performance bewirken.

Manchmal macht es sogar Sinn, einen freistehenden Block ohne 
if/switch/while/for anzulegen, einfach nur um den Scope zu begrenzen, 
innerhalb dessen ein Objekt gültig ist. Wenn man das eine Weile in C++ 
macht, gewöhnt man sich auch in C an, die Variablen strikt im Scope zu 
begrenzen, auch wenn es dort weniger starke Auswirkungen hat.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Hans schrieb:
> Wenn man sämtliche Objekte gleich zur Beginn der Funktion anlegt (und
> implizit erst am Ende der Funktion zerstört) kann das deutlich
> Performance kosten.

Auch der umgekehrte Fall ist möglich: In einer Schleife unnötigerweise
tausendmal ein Objekt zu konstruieren und zu destruieren kostet mehr
Zeit als dies jeweils nur einmal außerhalb der Schleife zu tun und
dasselbe Objekt tausendmal widerzuverwenden. Es hängt halt immer vom
konkreten Anwendungsfall ab.

> Dabei geht es nicht nur um Speicher, sondern ggf. auch andere Ressourcen
> (Stichwort RAII). Ein gutes Beispiel sind Lock-Guards, also Objekte, die
> ein Mutex im Konstruktor belegen und im Destruktor wieder freigebenen.

Für solche Dinge verwende auch ich eng begrenzte Scopes, da diese
Vorgehensweise nicht nur eleganter ist, sondern auch Fehler durch
vergessene Rückgabe der Ressource bereits im Keim erstickt.

von Stefan F. (Gast)


Lesenswert?

> Manchmal macht es sogar Sinn, einen freistehenden Block ohne
> einfach nur um den Scope zu begrenzen

Das mache ich oft, auch in anderen Programmiersprachen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.