Historický kontext: Měli bychom si pamatovat, že Dijkstra napsal Goto považováno za škodlivé v roce 1968, kdy mnoho programátorů používalo goto
jako náhrada za strukturované programování (if
, while
, for
, atd.).
Je to o 44 let později a je vzácné najít toto použití goto
v divočině. Strukturované programování již dávno zvítězilo.
Analýza případu:
Příklad kódu vypadá takto:
SETUP...
again:
COMPUTE SOME VALUES...
if (cmpxchg64(ptr, old_val, val) != old_val)
goto again;
Strukturovaná verze vypadá takto:
SETUP...
do {
COMPUTE SOME VALUES...
} while (cmpxchg64(ptr, old_val, val) != old_val);
Když se podívám na strukturovanou verzi, okamžitě si říkám:"to je smyčka". Když se podívám na goto
verzi, považuji to za přímku s případem „zkuste to znovu“ na konci.
goto
verze má obě SETUP
a COMPUTE SOME VALUES
na stejném sloupci, což zdůrazňuje, že většinu času řídicí tok prochází oběma. Strukturovaná verze uvádí SETUP
a COMPUTE SOME VALUES
na různých sloupcích, což zdůrazňuje, že kontrola jimi může procházet odlišně.
Otázkou je, jaký důraz chcete v kódu klást? Můžete to porovnat s goto
pro zpracování chyb:
Strukturovaná verze:
if (do_something() != ERR) {
if (do_something2() != ERR) {
if (do_something3() != ERR) {
if (do_something4() != ERR) {
...
Přejít na verzi:
if (do_something() == ERR) // Straight line
goto error; // |
if (do_something2() == ERR) // |
goto error; // |
if (do_something3() == ERR) // |
goto error; // V
if (do_something4() == ERR) // emphasizes normal control flow
goto error;
Vygenerovaný kód je v podstatě stejný, takže to můžeme považovat za typografický problém, jako je odsazení.
Velmi dobrá otázka a myslím, že definitivní odpověď může poskytnout pouze autor (autoři). Přidám trochu své spekulace tím, že řeknu, že to mohlo začít tím, že se to začalo používat pro zpracování chyb, jak vysvětlil @Izkata, a brány pak byly otevřené pro použití i pro základní smyčky.
Použití zpracování chyb je podle mého názoru legitimní v programování systémů. Funkce postupně přiděluje paměť, a pokud dojde k chybě, bude goto
příslušný štítek pro uvolnění zdrojů v opačném pořadí od tohoto bodu.
Pokud tedy dojde k chybě po prvním přidělení, přeskočí se na poslední štítek chyby, aby se uvolnil pouze jeden zdroj. Podobně, pokud k chybě dojde po poslední alokaci, přeskočí na první štítek chyby a spustí se odtamtud, přičemž uvolní všechny prostředky až do konce funkce. Takový vzor pro zpracování chyb je stále třeba používat opatrně, zejména při úpravě kódu, valgrind a unit testy jsou vysoce doporučeny. Ale je pravděpodobně čitelnější a udržitelnější než alternativní přístupy.
Jedno zlaté pravidlo použití goto
je vyhnout se tzv. špagetovému kódu. Zkuste nakreslit čáry mezi jednotlivými goto
prohlášení a jeho příslušné označení. Pokud se čáry kříží, dobře, překročili jste čáru :). Takové použití goto
je velmi špatně čitelný a je častým zdrojem obtížně sledovatelných chyb, protože by se nacházely v jazycích jako BASIC, které se na něj spoléhaly při řízení toku.
Pokud uděláte jen jednu jednoduchou smyčku, nedojde k překřížení čar, takže je stále čitelný a udržovatelný a stává se převážně záležitostí stylu. Vzhledem k tomu, že je lze stejně snadno provést pomocí klíčových slov smyčky poskytnutých v jazyce, jak jste uvedli ve své otázce, mým doporučením by bylo vyhnout se použití goto
pro smyčky, jednoduše proto, že for
, do/while
nebo while
konstrukce jsou svým designem elegantnější.
V případě tohoto příkladu se domnívám, že šlo o dovybavení podpory SMP do kódu, který byl původně napsán způsobem, který není bezpečný pro SMP. Přidání goto again;
cesta je mnohem jednodušší a méně invazivní než restrukturalizace funkce.
Nemohu říci, že se mi tento styl moc líbí, ale také si myslím, že je scestné vyhýbat se goto
z ideologických důvodů. Jeden speciální případ goto
použití (odlišné od tohoto příkladu) je kde goto
se používá pouze k pohybu vpřed ve funkci, nikdy zpět. Tato třída použití nikdy nevede ke konstrukci smyček vznikajících z goto
a je to téměř vždy ten nejjednodušší a nejjasnější způsob, jak implementovat potřebné chování (což je obvykle vyčištění a vrácení chyby).