Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Gotbread

Alter Hase

Beiträge: 421

Beruf: Student (Etechnik) + Hiwi

  • Private Nachricht senden

31

09.09.2009, 20:59

können alle durch den sinnvollen einnsatz einer zusätzlichen funktion
oder einer dummy-schleife vermieden werden. zeig mir ein beispiel wo
man wirklich goto braucht !
Mfg Goti
www.gotbread.bplaced.net
viele tolle spiele kostenlos, viele hardware-basteleien :)

"Es ist nicht undicht, es läuft über" - Homer Simpson

Helmut

5x Contest-Sieger

Beiträge: 692

Wohnort: Bielefeld

  • Private Nachricht senden

32

09.09.2009, 21:34

gotos können zwar immer durch andere Konstrukte ersetzt werden, nicht immer wird der Code dann aber auch leserlicherer. (wenn du willst kann ich Beispiele geben)
In Anfängerbücher oder so sollte man aber trotzdem gotos verbieten, damit die erstmal die korrekte Benutzung von Funktionen und Kontrollstrukturen lernen :)

Ciao
Sei stets geduldig gegenüber Leuten, die nicht mit dir übereinstimmen. Sie haben ein Recht auf ihren Standpunkt - trotz ihrer lächerlichen Meinung. (F. Hollaender)

Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

33

09.09.2009, 21:35

In einem Contest wer den unleserlichsten Code schreibt ;)

Ne aber stimmt schon. Es gibt immer eine bessere Alternative zu goto

EDIT:
@Helmut: Ja die Beispiele würden mich mal interessieren.

Helmut

5x Contest-Sieger

Beiträge: 692

Wohnort: Bielefeld

  • Private Nachricht senden

34

09.09.2009, 22:01

Ok, mal etwas aus meinen Projekten.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
            for(int Frame = 0; Frame < FutureFrames; Frame++)
            {
                if(cGS != MaxGS && Frame%5 == 0)//Nur jeden 5. Frame Tasten ändern, sonst sind die Routen zu ähnlich

                    for(int i = cGS-1; i >= 0; i--)
                    {
                        if(!GS[i].Players[Me].Alive)
                            continue;
                        for(int j = 0; j < 6; j++)
                        {
                            if(GS[i].Players[Me].LastKeys == j)
                                continue;
                            GS[cGS] = GS[i];
                            GS[cGS].Players[Me].LastKeys = j;
                            if(Frame == 0)
                                GS[cGS].StartKeys = j;
                            if(++cGS == MaxGS)
                                goto Next;
                        }
                    }
Next:
                for(int i = 0; i < cGS; i++)
                {
                    if(!GS[i].Players[Me].Alive)
                        continue;
                    if(GS[i].CanPlayerShoot(You))
                        GS[i].Shoot(You)->PlayerOwner = -1;//damit der Gegner in unserer Vision ganz viel schießt (kein Schusslimit)

                    GS[i].Move(Me, GS[i].Players[Me].LastKeys | K_Shoot, GS_.Players[You].LastKeys /*& ~K_Shoot*/);

                    if(!GS[i].Players[Me].Alive && GS[i].FrameNo < GS[i].MinDieTime)
                        GS[i].MinDieTime = GS[i].FrameNo;
                    if(!GS[i].Players[You].Alive && GS[i].Players[You].RespawnTimer == 99)
                    {
                        if(GS[i].FrameNo > GS[i].MaxKillTime)
                            GS[i].MaxKillTime = GS[i].FrameNo;
                    }
                }
            }

Man könnte natürlich das goto durch i=-1;break; ersetzen, aber leserlicher wär das wohl kaum. Ne Auslagerung in eine Funktion ist auch nicht sonderlich sinnvoll.

Anderes Beispiel:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    std::vector<Expression*> Ops(...);
    for(size_t i = 0; i < Ops.size();)
    {
        assert(Ops[i]->IsBoolean());
        if(*Ops[i] == *Number(0))
            return Number(0);
        if(*Ops[i] == *Number(1))
            goto Erase;
        if(Ops[i]->Is<OpLogicalAnd>())
        {
            Ops.insert(Ops.begin()+i+1, ((OpLogicalAnd*)Ops[i])->Ops.begin(), ((OpLogicalAnd*)Ops[i])->Ops.end());
            goto Erase;
        }
        if(Ops[i]->Is<OpLogicalOr>())
        {
            std::vector<Expression*>& OldOrs = ((OpLogicalOr*)Ops[i])->Ops;
            std::vector<Expression*> NewOrs(OldOrs.size());
            for(size_t j = 0; j < OldOrs.size(); j++)
            {
                Ops[i] = OldOrs[j];
                NewOrs[j] = LogicalAnd(Ops);
            }
            return LogicalOr(NewOrs);
        }

        //doppelt?

        for(size_t j = 0; j < i; j++)
            if(*Ops[i] == *Ops[j])
                goto Erase;

        i++;
        continue;
Erase:
        Ops.erase(Ops.begin()+i);
    }
    //...


Ciao
Sei stets geduldig gegenüber Leuten, die nicht mit dir übereinstimmen. Sie haben ein Recht auf ihren Standpunkt - trotz ihrer lächerlichen Meinung. (F. Hollaender)

Gotbread

Alter Hase

Beiträge: 421

Beruf: Student (Etechnik) + Hiwi

  • Private Nachricht senden

35

09.09.2009, 22:49

erase();
return;

;)
Mfg Goti
www.gotbread.bplaced.net
viele tolle spiele kostenlos, viele hardware-basteleien :)

"Es ist nicht undicht, es läuft über" - Homer Simpson

36

09.09.2009, 23:28

Zitat von »"Helmut"«

Ne Auslagerung in eine Funktion ist auch nicht sonderlich sinnvoll.
Wieso nicht? Meiner Meinung nach ist deine Funktion viel zu gross und zu unübersichtlich. Eine Aufteilung in 3 Funktionen, die natürlich passende Namen hätten, fände ich sowieso angebracht. Ich habe mal einen Vorschlag, aber ohne das konkrete Problem zu kennen, ist das nicht so einfach. Tatsache ist aber, dass das goto durch ein return ersetzt werden kann.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
void Function2(Parameter)
{
    for(int i = cGS-1; i >= 0; i--) 
    { 
        if(!GS[i].Players[Me].Alive) 
            continue; 
        for(int j = 0; j < 6; j++) 
        { 
            if(GS[i].Players[Me].LastKeys == j) 
                continue; 
            GS[cGS] = GS[i]; 
            GS[cGS].Players[Me].LastKeys = j; 
            if(Frame == 0) 
                GS[cGS].StartKeys = j; 
            if(++cGS == MaxGS) 
                return; //goto Next; 

        } 
    } 
}

void Function3(Parameter)
{
    for(int i = 0; i < cGS; i++) 
    { 
        if(!GS[i].Players[Me].Alive) 
            continue; 
        if(GS[i].CanPlayerShoot(You)) 
            GS[i].Shoot(You)->PlayerOwner = -1;
        GS[i].Move(Me, GS[i].Players[Me].LastKeys | K_Shoot, GS_.Players[You].LastKeys /*& ~K_Shoot*/); 

        if(!GS[i].Players[Me].Alive && GS[i].FrameNo < GS[i].MinDieTime) 
            GS[i].MinDieTime = GS[i].FrameNo; 
        if(!GS[i].Players[You].Alive && GS[i].Players[You].RespawnTimer == 99) 
        { 
            if(GS[i].FrameNo > GS[i].MaxKillTime) 
                GS[i].MaxKillTime = GS[i].FrameNo; 
        } 
    }
}

void Function()
{
    for(int Frame = 0; Frame < FutureFrames; Frame++) 
    { 
        if(cGS != MaxGS && Frame%5 == 0)
            Function2(Argumente);
            
        Function3(Argumente); 
    }   
}


BTW: Kann das Forum immer noch nicht mit mehreren /* */ umgehen? :roll:

Helmut

5x Contest-Sieger

Beiträge: 692

Wohnort: Bielefeld

  • Private Nachricht senden

37

10.09.2009, 00:00

@Gotbread
Das funktioniert nicht.

@Nexus
Naja, einen Codeteil, der nur von einer Stelle aus aufgerufen wird, in eine Funktion auszulagern ist nicht sonderlich sinnvoll. Wenn man einen bestimmten Codeteil benennen will, genügt ein Kommentar. Ein Code mit vielen kleinen Funktionen kann nicht übersichtlicher sein, als das Äquivalent, bei dem die Funktionen so weit zusammengefasst sind, wie möglich. Aber selbst wenn, was ist mit dem zweiten Beispiel? Würdest du den Inhalt der Minischleife auch in ne Funktion packen (+bool Rückgabewert)

Oder was empfehlt ihr hier:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
Again:
        foreach(std::vector<bla*>, i, Bla)
            foreach(std::vector<dword>, j, (*i)->Blub)
                if(blubber(*j) == 0)
                {
                    hui(*j);
                    goto Again;
                }

foreach ist nen Makro, stellt euch das einfach mit Iteratoren vor :)
Funktion wäre hier lächerlich, ein extra bool-Wert+Schleife würde die Sache deutlich komplizierter erscheinen lassen, als sie es ist.

Ciao
Sei stets geduldig gegenüber Leuten, die nicht mit dir übereinstimmen. Sie haben ein Recht auf ihren Standpunkt - trotz ihrer lächerlichen Meinung. (F. Hollaender)

38

10.09.2009, 00:03

Zum zweiten Code: Wäre es dort nicht möglich, die Elemente erst am Schluss zu entfernen? Das würde verschiedene Aufgaben trennen und wäre nebenbei noch performanter, da erase() in der Mitte von std::vector nicht gerade schnell läuft. Wenn ich das richtig sehe, könntest du damit die Komplexität von quadratisch auf linear herunterschrauben. Also eventuell zuerst die zu löschenden Elemente markieren oder - falls möglich - danach direkt die Löschbedingungen anwenden. Ganz elegant in Zusammenarbeit mit std::remove_if().

Zitat von »"Helmut"«

@Nexus
Naja, einen Codeteil, der nur von einer Stelle aus aufgerufen wird, in eine Funktion auszulagern ist nicht sonderlich sinnvoll. Wenn man einen bestimmten Codeteil benennen will, genügt ein Kommentar. Ein Code mit vielen kleinen Funktionen kann nicht übersichtlicher sein, als das Äquivalent, bei dem die Funktionen so weit zusammengefasst sind, wie möglich.
Das sehe ich anders. Wenn ich eine kleine Funktion habe, ist normalerweise auch die Schnittstelle (Parameter und Rückgabetyp) kleiner. Dadurch sieht man schneller, was die Funktion verändern kann, worauf sie Zugriff hat. Die Komplexität sinkt, die Funktion erhält einen genau definierten Aufgabenbereich. Const-Correctness kann härter angewandt werden, Exceptionsicherheit wird einfacher. Die Wartung wird erleichtert, da erstens Fehler besser eingeschränkt werden können und zweitens weniger Seiteneffekte vorhanden sind, auf die man bei einer Anpassung des Codes auch noch Rücksicht nehmen muss.

Zudem ist es bei mir schon ab und zu vorgekommen, dass ich einen Teil einer Funktion sonst irgendwo gebraucht habe, und dann direkt die kleinere Funktion aufrufen konnte, anstatt Code zu duplizieren.

Helmut

5x Contest-Sieger

Beiträge: 692

Wohnort: Bielefeld

  • Private Nachricht senden

39

10.09.2009, 00:31

Zitat von »"Nexus"«

Zum zweiten Code: Wäre es dort nicht möglich, die Elemente erst am Schluss zu entfernen? Das würde verschiedene Aufgaben trennen und wäre nebenbei noch performanter, da erase() in der Mitte von std::vector nicht gerade schnell läuft. Wenn ich das richtig sehe, könntest du damit die Komplexität von quadratisch auf linear herunterschrauben. Also eventuell zuerst die zu löschenden Elemente markieren oder - falls möglich - danach direkt die Löschbedingungen anwenden. Ganz elegant in Zusammenarbeit mit std::remove_if().

Naja Markierung ginge nicht so gut. Sind schließlich Pointer. Höchstens indem man in nem Set die Indizes merkt oder so.. Außerdem werden am Ende der Schleife das Aktuelle mit allen vorherigen Elementen verglichen, es würde also den Algo ändern.

Zitat


Das sehe ich anders. Wenn ich eine kleine Funktion habe, ist normalerweise auch die Schnittstelle (Parameter und Rückgabetyp) kleiner. Dadurch sieht man schneller, was die Funktion verändern kann, worauf sie Zugriff hat. Die Komplexität sinkt, die Funktion erhält einen genau definierten Aufgabenbereich. Const-Correctness kann härter angewandt werden, Exceptionsicherheit wird einfacher. Die Wartung wird erleichtert, da erstens Fehler besser eingeschränkt werden können und zweitens weniger Seiteneffekte vorhanden sind, auf die man bei einer Anpassung des Codes auch noch Rücksicht nehmen muss.

Zudem ist es bei mir schon ab und zu vorgekommen, dass ich einen Teil einer Funktion sonst irgendwo gebraucht habe, und dann direkt die kleinere Funktion aufrufen konnte, anstatt Code zu duplizieren.

Ich mache das doch genauso. Wann immer es Sinn macht, etwas auszulagern, tue ich das auch. Im Beispiel oben macht es aber meiner Meinung nach keinen Sinn. Ich wüsste nichtmal, wie ich die Funktion nennen sollte.
Mein Punkt ist ja nur, dass gotos nicht soooooo böse sind, wie viele denken :)

Ciao
Sei stets geduldig gegenüber Leuten, die nicht mit dir übereinstimmen. Sie haben ein Recht auf ihren Standpunkt - trotz ihrer lächerlichen Meinung. (F. Hollaender)

40

10.09.2009, 00:37

Das schlimmste am Code finde ich noch, dass quasi keine Kommentare drin vor kommen. Also wenn ich doch so dreifach verschachtelte Konstrukte habe, würde ich z.B. an die Schleifen dran schreiben, welche Aufgabe die haben und generell viel mehr Kommentieren.
Lieber dumm fragen, als dumm bleiben!

Werbeanzeige