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

41

10.09.2009, 00:40

wenn ich deinen cleanup code an die stelle des aufrufs kopiere
(zwei zeilen insgesamt doppelt, hiiiilfe) und noch ein return einfüge,
klappt das schon.

C-/C++-Quelltext

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


no problem

goto kann:

zurückspringen: da nehm ich ne schleife
vorspringen: if (diesunddas) {}

eine schleifenebene verlassen: break;
mehrere schleifen verlassen: return;
mehrere scleifen ohne funktion verlassen: EVIL, unübersichtlich!

den ersten code kann man bestimmt umschreiben, bin grade zu faul.
theoretisch(?) lässt es sich jedoch immer ersetzen. goto, throw und
const_cast sind die 3 unschönsten sachen imho.
Mfg Goti
www.gotbread.bplaced.net
viele tolle spiele kostenlos, viele hardware-basteleien :)

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

42

10.09.2009, 00:41

Zitat von »"Helmut"«

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;
                }

Mir scheint, du hast etwas gegen Funktionen. ;)

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
bool IsHuiThere()
{
    foreach(std::vector<bla*>, i, Bla)
        foreach(std::vector<dword>, j, (*i)->Blub)
            if(blubber(*j) == 0)
            {
                hui(*j); 
                return true; 
            }
    
    return false;
}

while (IsHuiThere());

Zugegeben, man kanns auch übertreiben, es gibt gotos, die gerechtfertigt sein können (ich sehe das dritte Beispiel als solches an, bei den anderen beiden finde ich es recht schwierig, den Code schnell verstehen zu können). Ich wollte in meinem Code auch schon goto verwenden, um aus tief verschachtelten Schleifen zu springen, aber ziemlich bald darauf hatte ich den Eindruck, eine zusätzliche Funktion wäre geeigneter. Ist natürlich auch etwas Glaubenssache, wie immer ist goto nicht grundsätzlich schlecht. Ich habe bisher aber in jedem Fall eine - meiner Ansicht nach - schönere Lösung gefunden.

Elegant an der Lösung des dritten Problems mit einer Funktion finde ich, dass man bei

C-/C++-Quelltext

1
while (IsHuiThere());
ziemlich schnell und ohne Kommentar sieht, was gemacht wird. Man muss sich allerdings an Leeranweisungen nach Schleifenköpfen gewohnt sein, sonst verwirrt das. :)
Hier kann sich das besonders auszahlen, wenn in der Funktion, die IsHuiThere() aufruft, noch einige andere Dinge gemacht werden.

Helmut

5x Contest-Sieger

Beiträge: 692

Wohnort: Bielefeld

  • Private Nachricht senden

43

10.09.2009, 01:11

@Gotbread
Du hast den Code nicht verstanden ;) Zugegebenermaßen ist er auch etwas unübersichtlich, aber nach dem erase() steht noch ein implizites continue. Außerdem will das dezente //... am Ende nicht vergessen werden :)

Und mir ist schon klar, dass jedes goto umgangen werden kann. Genauso wie for, do, class, private... Wenn man will kann man auch gleich Assembler benutzen. Der Sinn dieser Schlüsselwörter (inklusive goto) ist aber, um Code besser lesbar zu machen. Und dein "i = Bla.begin(), j = (*i)->Blub;" ist nunmal schwieriger zu verstehen, also ein einfaches goto. (und nebenbei noch falsch, du hast das j++ am Ende vergessen)

Und außerdem muss eine verschachtelte Schleife nicht unübersichtlich sein. Wenn man durch zwei Dimensionen eines Bildes zB iteriert, ist das nicht komplizierter als ne normale Schleife.

Wenn ich C++ neu designen könnte würde ich die Kombination von breaks und continues einführen. Z.B. ein break,break; (man beachte das Komma) um aus einer verschachtelten Schleife springen zu können. Oder auch break, continue; Dann gäb's für mich kaum noch Gründe für gotos :) (Einen Fall gäbs immer noch, ist aber schwer zu erklären und will wahrscheinlich eh keiner wissen.. :))


@Nexus
Das ist natürlich prinzipiell eine Lösung :) Ich versteh nur nicht, warum niemand was gegen breaks und continue hat, bei ner verschachtelten Schleife und nem goto aber gleich feuerrot sieht :) Man muss doch nicht alles glauben, was man mal in einem C++-Buch gelernt hat :)

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)

44

10.09.2009, 01:16

Zitat von »"Helmut"«

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.
Ich meinte auch eher ausserhalb. Aber ich kenn dein Problem nicht genau genug, um spezifisch zu antworten. Jedoch wäre mir bereits die Verringerung der Zeitkomplexität Anreiz genug, wenigstens darüber nachzudenken. Auch das "mit allen vorherigen vergleichen" macht mich etwas stutzig, meinst du nicht, hier gibt es eine effizientere Lösung? Sorry, falls ich mich total irre, kann gut sein, dass alles okay ist. Ich bin halt noch schnell skeptisch, wenn ein Algorithmus viele solche Operationen beinhält. ;)

Zitat von »"Helmut"«

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.
Wie würdest du die For-Schleifen beschreiben, was tun die? Einen sinnvollen Namen zu finden sollte eigentlich möglich sein. Das Problem hättest du ja auch, wenn du Kommentare statt eigene Funktionen einsetzen würdest.

Wie gesagt: goto kann okay sein. Aber wenn eine Funktion so gross ist und darin Sprünge vorkommen, finde ich es recht schwierig, gleich alles zu überblicken. Es kann auch leicht passieren, dass mal etwas übersehen wird (eben auch die erwähnten Seiteneffekte). Und Debugging wird wirklich viel einfacher, wenn man plötzlich nur noch halb so viele Stackvariablen und Parameter hat, von denen einige sogar durch const eingeschränkt sind. Auch die Anzahl Ablaufpfade verringert sich und das Prüfen von Pre- und Postconditions über assert ist viel weniger komplex, weil hier jede Funktion selbst zuständig ist und sich der Ausführer eines Algorithmus keine Gedanken mehr um solche Dinge machen muss.

Und ich gehöre auch nicht zu der Sorte Menschen, die Funktionen mit mehr als einer gewissen Anzahl Zeilen grundsätzlich immer böse finden. Meistens tendieren diese Funktionen aber dazu, eher komplizierte Dinge zu tun (wie z.B. verschachtelte Schleifen mit if-Bedingungen). Kompliziert im Sinne von: Man braucht viel Zeit, um Code zu verstehen, weil für den Algorithmus irrelevante Details nicht ausgelagert wurden - und die Gefahr der oben erwähnten Probleme ist grösser. Aus diesem Grund versuche ich, so weit sinnvoll aufzuteilen. Man findet dann auch die Funktionalität leichter wieder, wenn man vernünftige Funktionsnamen hat. Klar, dass "sinnvoll" wieder subjektiv ist, in diesem Punkt haben wir wohl eine etwas andere Ansicht.

Also zusammengefasst: Es gibt (wie für fast alles) berechtigte Anwendungsgebiete von goto. Die Alternativen scheinen mir in vielen Fällen aber nicht schlimm, besitzen jedoch ein paar hübsche Nebeneffekte. Das ist der Grund, wieso ich kaum goto verwende - nicht weil ich dem Dogma folgen will, so einer bin ich nicht. :p

Steven77

Alter Hase

Beiträge: 515

Wohnort: Münster - Gievenbeach

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

45

10.09.2009, 09:34

Zumindest wieder etwas in Richtung Topic:

Zitat von »"Gotbread"«

[...] übrigens wird const_cast sogar in einem buch [...] empfohlen. hatte was mit der const und nicht-const version von operator[] zu tun oder sowas


Das ist korrekt! Scott Meyers legt dabei den Fokus auf Code-Wiederverwendung anstelle von -Duplizierung: Nicht selten hat man zwei Versionen von Methoden (es geht also nicht nur um den []-Operator), eine const eine nicht-const, die aber dieselbe Logik bieten. Um eben diese Logik nicht doppelt zu implementieren, ruft die nicht-const-Version die const-Version auf. Hierfür wird in der nicht-const-Version erst der this-Zeiger "geconstet", um die const-Version der Methode aufzurufen, und anschließend das Ergebnis per const_cast zurückgegeben. Das ist an dieser Stelle sauberes Programmieren, weil nicht-const-Methoden immer const-Methoden aufrufen dürfen und das Vorhandensein der nicht-const-Version ja bereits impliziert, dass das Objekt geändert werden darf. Insofern ist das "Zurücktransformieren" (von const in nicht-const) per const_cast keine böse Sache, sondern eine ganz saubere Angelegenheit. Scott Meyers argumentiert natürlich etwas schlüssiger, als ich das jetzt hier aus dem Kopf hinkriege. Ansonsten, so wie auch hier, sollte man sich aber immer ganz bewusst sein, was man mit nem const_cast bewirkt und überhaupt bezwecken will.
Kommen Sie nie mit einem Schwert zu einer Schießerei.

drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

46

10.09.2009, 13:19

Also ich habe das goto in einer ähnlichen Situation, wie Helmut benutzt. Eine relativ kleine Funktion, aber ein paar Verschachtelungen und da wollte ich halt rausspringen. Klar wäre es anderst gegangen mit Funktion o.ä.
Aber wenn der Aufwand und Verständlichkeit darunter leidet, dass man goto umgeht, dann ist goto die bessere Wahl.

Das Problem ist halt, dass viele goto für andere Zwecke benutzt, wo eben die Alternativen um einiges Natürlicher sind, als goto und eben von dieser Überhäuften falschen Verwendung wird halt oft gewarnt. Und imo kann man einem Neuling ohne weiteres beibringe, dass goto "böse" ist, dann gewöhnt er sich so Zeugs gar nicht erst an. Aber wenn man mal genug Erfahrung hat, dann gilt das gleiche wie immer. Wenn man weiss, was man tut, dann sind alle Sprachmittel erlaubt.

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

47

10.09.2009, 13:42

Zitat von »"drakon"«

Aber wenn man mal genug Erfahrung hat, dann gilt das gleiche wie immer. Wenn man weiss, was man tut, dann sind alle Sprachmittel erlaubt.


Diese Einstellung kann dir auch schnell mal den Job kosten! :)

drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

48

10.09.2009, 14:06

Zitat von »"David_pb"«

Zitat von »"drakon"«

Aber wenn man mal genug Erfahrung hat, dann gilt das gleiche wie immer. Wenn man weiss, was man tut, dann sind alle Sprachmittel erlaubt.


Diese Einstellung kann dir auch schnell mal den Job kosten! :)


Natürlich habe ich das auf den Hobby Bereich bezogen. ;)
Coding Guidelines sind natürlich vorrangig.

Gotbread

Alter Hase

Beiträge: 421

Beruf: Student (Etechnik) + Hiwi

  • Private Nachricht senden

49

10.09.2009, 14:16

Zitat von »"Helmut"«


@Gotbread
Du hast den Code nicht verstanden


ich habe mir nur das goto angeguckt, war schon spät.

und in meine "guideline" hat ein goto nichts verloren. in einer anderen sprache
z.b. (inline)assembler springe ich auch wie wild rum.
Mfg Goti
www.gotbread.bplaced.net
viele tolle spiele kostenlos, viele hardware-basteleien :)

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

Werbeanzeige