340 Stimmen

Wozu dienen geschweifte Klammern (d.h. {}) in einer einzeiligen if- oder Schleife?

Ich lese gerade einige Vorlesungsunterlagen meines C++-Dozenten, und er schrieb Folgendes:

  1. Einrückung verwenden // OK
  2. Verlassen Sie sich nie auf den Vorrang von Operatoren - Verwenden Sie immer Klammern // OK
  3. Verwenden Sie immer einen { }-Block - auch für eine einzelne Zeile // nicht OK Warum?
  4. Const-Objekt auf der linken Seite des Vergleichs // OK
  5. Vorzeichenlose Variablen, die >= 0 sind, verwenden // netter Trick
  6. Zeiger nach dem Löschen auf NULL setzen - Doppelter Löschschutz // nicht schlecht

Die 3. Technik ist mir nicht klar: Was würde ich gewinnen, wenn ich eine Zeile in a { ... } ?

Nehmen wir zum Beispiel diesen merkwürdigen Code:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}

und ersetzen sie durch:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;

Was ist der Vorteil der 1. Version?

5voto

Konrad Borowski Punkte 10645

Denn wenn Sie zwei Aussagen ohne {} kann man leicht ein Problem übersehen. Nehmen wir an, dass der Code wie folgt aussieht.

int error = 0;
enum hash_type hash = SHA256;
struct hash_value *hash_result = hash_allocate();

if ((err = prepare_hash(hash, &hash_result))) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &client_random)) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &server_random)) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &exchange_params)) != 0)
    goto fail;
    goto fail;
if ((err = hash_finish(hash)) != 0)
    goto fail;

error = do_important_stuff_with(hash);

fail:
hash_free(hash);
return error;

Sieht gut aus. Das Problem ist wirklich leicht zu übersehen, vor allem wenn die Funktion, die den Code enthält, viel größer ist. Das Problem ist, dass goto fail wird bedingungslos ausgeführt. Sie können sich leicht vorstellen, wie frustrierend das ist (und Sie fragen, warum der letzte hash_update scheitert immer, schließlich sieht alles gut aus in hash_update Funktion).

Das bedeutet jedoch nicht, dass ich für die Hinzufügung von {} überall (meiner Meinung nach, da {} überall ist ärgerlich). Das kann zwar zu Problemen führen, hat es aber bei meinen eigenen Projekten nie getan, da mein persönlicher Codierungsstil Conditionals ohne {} wenn sie nicht in der gleichen Zeile stehen (ja, ich stimme zu, dass mein Kodierungsstil unkonventionell ist, aber ich mag ihn, und ich verwende den Kodierungsstil des Projekts, wenn ich zu anderen Projekten beitrage). Damit ist der folgende Code in Ordnung.

if (something) goto fail;

Aber nicht die folgende.

if (something)
    goto fail;

4voto

Tom Tanner Punkte 9075

Wrt 6: Es ist sicherer, weil das Löschen eines Null-Zeigers ein No-op ist. Also, wenn Sie versehentlich durch diesen Weg zweimal gehen, werden Sie nicht verursachen Speicher Korruption sein Freigeben von Speicher, die entweder frei ist oder etwas anderes zugeordnet wurde.

Dies ist vor allem ein Problem bei statischen Dateibereichsobjekten und Singletons, die keine eindeutige Lebensdauer haben und bekanntermaßen neu erstellt werden, nachdem sie zerstört wurden.

In den meisten Fällen können Sie dies vermeiden, indem Sie auto_ptrs verwenden

4voto

MikeFHay Punkte 8021

Ich mag Luchian's akzeptierte Antwort . Ich habe nämlich auf die harte Tour gelernt, dass er Recht hat, und verwende daher immer geschweifte Klammern, auch bei einzeiligen Blöcken. Allerdings mache ich persönlich eine Ausnahme, wenn ich einen Filter schreibe, wie in Ihrem Beispiel. Dies:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}

sieht für mich unübersichtlich aus. Es trennt die "for"-Schleife und die "if"-Anweisung in separate Aktionen auf, obwohl Sie eigentlich nur eine einzige Aktion beabsichtigen: alle durch 2 teilbaren ganzen Zahlen zu zählen. In einer ausdrucksstärkeren Sprache könnte dies etwa so geschrieben werden:

j = [1..100].filter(_%2 == 0).Count

In Sprachen, die keine Abschlüsse haben, kann der Filter nicht in einer einzigen Anweisung ausgedrückt werden, sondern muss eine für Schleife, gefolgt von einer si Erklärung. Es ist jedoch immer noch eine Aktion im Kopf des Programmierers, und ich glaube, das sollte sich im Code widerspiegeln, etwa so:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
  if (i % 2 == 0)
{
    j++;
}

4voto

Drona Punkte 6442

Es macht Ihren Code lesbarer, indem es den Anwendungsbereich Ihrer Schleifen und bedingten Blöcke klar definiert. Es bewahrt Sie auch vor versehentlichen Fehlern.

4voto

Blacktiger Punkte 1245

Eine Möglichkeit, die in den vorangegangenen Antworten beschriebenen Fehler zu vermeiden, besteht darin, das, was passieren soll, wenn Sie keine geschweiften Klammern verwenden, inline zu schreiben. Dadurch wird es viel schwieriger, die Fehler zu übersehen, wenn Sie versuchen, den Code zu ändern.

if (condition) doSomething();
else doSomethingElse();

if (condition) doSomething();
    doSomething2(); // Looks pretty obviously wrong
else // doSomethingElse(); also looks pretty obviously wrong

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X