Als ich heute eine Codeüberprüfung für einen Kollegen durchführte, sah ich etwas Besonderes. Er hatte seinen neuen Code mit solchen geschweiften Klammern umgeben:
Constructor::Constructor()
{
existing code
{
New code: do some new fancy stuff here
}
existing code
}
Was ist das Ergebnis davon, wenn überhaupt? Was könnte der Grund dafür sein? Woher kommt diese Gewohnheit?
Bearbeiten:
Aufgrund der Eingabe und einiger Fragen unten habe ich das Gefühl, dass ich einige zur Frage hinzufügen muss, obwohl ich bereits eine Antwort markiert habe.
Die Umgebung besteht aus eingebetteten Geräten. Es gibt viel alten C-Code in C ++ - Kleidung. Es gibt viele C ++ C-Entwickler.
In diesem Teil des Codes gibt es keine kritischen Abschnitte. Ich habe es nur in diesem Teil des Codes gesehen. Es werden keine größeren Speicherzuordnungen vorgenommen, nur einige gesetzte Flags und ein bisschen Twiddling.
Der Code, der von geschweiften Klammern umgeben ist, lautet wie folgt:
{
bool isInit;
(void)isStillInInitMode(&isInit);
if (isInit) {
return isInit;
}
}
(Kümmere dich nicht um den Code, halte dich einfach an die geschweiften Klammern ...;)) Nach den geschweiften Klammern gibt es noch ein bisschen Twiddling, Zustandsprüfung und grundlegende Signalisierung.
Ich sprach mit dem Typen und seine Motivation war es, den Umfang von Variablen, Namenskonflikten und anderen, die ich nicht wirklich erfassen konnte, einzuschränken.
Aus meiner Sicht erscheint dies ziemlich seltsam und ich denke nicht, dass die geschweiften Klammern in unserem Code enthalten sein sollten. Ich habe in allen Antworten einige gute Beispiele dafür gesehen, warum man Code mit geschweiften Klammern umgeben kann, aber sollten Sie den Code nicht stattdessen in Methoden unterteilen?
quelle
Antworten:
Es ist manchmal schön, da es Ihnen einen neuen Bereich gibt, in dem Sie neue (automatische) Variablen "sauberer" deklarieren können.
In
C++
dieser ist vielleicht nicht so wichtig , da Sie überall neue Variablen einführen können, aber vielleicht ist die Gewohnheit ausC
, wo man nicht diese bis C99 tun konnte. :) :)Da
C++
es Destruktoren gibt, kann es auch nützlich sein, Ressourcen (Dateien, Mutexe usw.) automatisch freizugeben, wenn der Bereich beendet wird, was die Dinge sauberer machen kann. Dies bedeutet, dass Sie eine gemeinsam genutzte Ressource für eine kürzere Dauer behalten können, als wenn Sie sie zu Beginn der Methode abgerufen hätten.quelle
Ein möglicher Zweck ist die Steuerung des Variablenbereichs . Und da Variablen mit automatischer Speicherung zerstört werden, wenn sie den Gültigkeitsbereich verlassen, kann ein Destruktor auch früher aufgerufen werden, als dies sonst der Fall wäre.
quelle
for
Aussagen, um eine kurzlebigeint i;
in C89 zu erstellen . Sicherlich schlagen Sie nicht vor, dass jederfor
in einer separaten Funktion sein sollte?Die zusätzlichen Klammern werden verwendet, um den Umfang der in den Klammern deklarierten Variablen zu definieren. Dies geschieht so, dass der Destruktor aufgerufen wird, wenn die Variable den Gültigkeitsbereich verlässt. Im Destruktor können Sie einen Mutex (oder eine andere Ressource) freigeben, damit andere ihn erwerben können.
In meinem Produktionscode habe ich ungefähr Folgendes geschrieben:
Wie Sie sehen, können Sie auf diese Weise
scoped_lock
eine Funktion verwenden und gleichzeitig ihren Umfang mithilfe zusätzlicher geschweifter Klammern definieren. Dies stellt sicher, dass der Code außerhalb der zusätzlichen Klammern zwar von mehreren Threads gleichzeitig ausgeführt werden kann , der Code innerhalb der geschweiften Klammern jedoch jeweils von genau einem Thread ausgeführt wird .quelle
scoped_lock
, die bei Ausnahmen zerstört wird. Normalerweise ziehe ich es vor, auch einen neuen Bereich für das Schloss einzuführen, aber in einigen Fällenunlock
ist dies sehr nützlich. Zum Beispiel, um eine neue lokale Variable innerhalb des kritischen Abschnitts zu deklarieren und sie später zu verwenden. (Ich weiß, ich bin spät dran, aber der VollständigkeitWie andere bereits betont haben, führt ein neuer Block einen neuen Bereich ein, der es einem ermöglicht, ein Stück Code mit eigenen Variablen zu schreiben, die den Namespace des umgebenden Codes nicht in den Papierkorb werfen und keine Ressourcen länger als nötig verwenden.
Es gibt jedoch noch einen weiteren guten Grund dafür.
Es geht einfach darum, einen Codeblock zu isolieren, der einen bestimmten (Unter-) Zweck erreicht. Es ist selten, dass eine einzelne Aussage einen von mir gewünschten Recheneffekt erzielt. normalerweise dauert es mehrere. Wenn ich diese in einen Block (mit einem Kommentar) setze, kann ich dem Leser (oft ich selbst zu einem späteren Zeitpunkt) sagen:
z.B
Sie könnten argumentieren, ich sollte eine Funktion schreiben, um all das zu tun. Wenn ich es nur einmal mache, fügt das Schreiben einer Funktion nur zusätzliche Syntax und Parameter hinzu. es scheint wenig Sinn zu haben. Stellen Sie sich dies als eine parameterlose, anonyme Funktion vor.
Wenn Sie Glück haben, verfügt Ihr Editor über eine Funktion zum Falten / Entfalten, mit der Sie den Block sogar ausblenden können.
Ich mache das die ganze Zeit. Es ist eine große Freude, die Grenzen des Codes zu kennen, den ich überprüfen muss, und noch besser zu wissen, dass ich keine der Zeilen betrachten muss, wenn dieser Block nicht der ist, den ich möchte.
quelle
Ein Grund könnte sein, dass die Lebensdauer von Variablen, die im neuen geschweiften Klammernblock deklariert sind, auf diesen Block beschränkt ist. Ein weiterer Grund, der mir in den Sinn kommt, ist die Möglichkeit, die Codefaltung im bevorzugten Editor zu verwenden.
quelle
Dies ist dasselbe wie ein
if
(oderwhile
etc ..) Block, nur ohneif
. Mit anderen Worten, Sie führen einen Bereich ein, ohne eine Kontrollstruktur einzuführen.Dieses "explizite Scoping" ist normalerweise in folgenden Fällen nützlich:
using
.Beispiel 1:
Wenn
my_variable
es sich um einen besonders guten Namen für zwei verschiedene Variablen handelt, die isoliert voneinander verwendet werden, können Sie durch explizites Scoping vermeiden, einen neuen Namen zu erfinden, um den Namenskonflikt zu vermeiden.Auf diese Weise können Sie auch vermeiden, dass Sie versehentlich
my_variable
aus dem vorgesehenen Bereich heraus verwenden.Beispiel 2:
Praktische Situationen, in denen dies nützlich ist, sind selten und weisen möglicherweise darauf hin, dass der Code für das Refactoring reif ist. Der Mechanismus ist jedoch vorhanden, falls Sie ihn jemals wirklich benötigen sollten.
Beispiel 3:
Dies kann für RAII in Fällen wichtig sein, in denen die Notwendigkeit, Ressourcen freizugeben, natürlich nicht auf Grenzen von Funktionen oder Kontrollstrukturen "fällt".
quelle
Dies ist sehr nützlich, wenn Sie Sperren mit Gültigkeitsbereich in Verbindung mit kritischen Abschnitten in der Multithread-Programmierung verwenden. Ihre in den geschweiften Klammern initialisierte Sperre mit Gültigkeitsbereich (normalerweise der erste Befehl) wird am Ende des Blockendes nicht mehr angezeigt, sodass andere Threads wieder ausgeführt werden können.
quelle
Alle anderen haben die Möglichkeiten von Scoping, RAII usw. bereits korrekt behandelt. Da Sie jedoch eine eingebettete Umgebung erwähnen, gibt es einen weiteren möglichen Grund:
Möglicherweise vertraut der Entwickler der Registerzuordnung dieses Compilers nicht oder möchte die Stapelrahmengröße explizit steuern, indem er die Anzahl der automatischen Variablen im Gültigkeitsbereich gleichzeitig begrenzt.
Hier
isInit
wird wahrscheinlich auf dem Stapel sein:Wenn Sie die geschweiften Klammern herausnehmen,
isInit
kann im Stapelrahmen Platz für reserviert sein, auch wenn dieser möglicherweise wiederverwendet werden könnte: Wenn viele automatische Variablen mit ähnlich lokalisiertem Bereich vorhanden sind und Ihre Stapelgröße begrenzt ist, kann dies ein Problem sein.Wenn Ihre Variable einem Register zugeordnet ist, sollte das Verlassen des Gültigkeitsbereichs einen starken Hinweis darauf liefern, dass das Register jetzt zur Wiederverwendung verfügbar ist. Sie müssten sich den Assembler ansehen, der mit und ohne geschweifte Klammern generiert wurde, um herauszufinden, ob dies einen echten Unterschied ausmacht (und ihn profilieren - oder auf Stapelüberlauf achten -, um festzustellen, ob dieser Unterschied wirklich wichtig ist).
quelle
Ich denke, andere haben das Scoping bereits behandelt, daher werde ich erwähnen, dass unnötige Klammern auch im Entwicklungsprozess einen Zweck erfüllen könnten. Angenommen, Sie arbeiten an einer Optimierung einer vorhandenen Funktion. Das Umschalten der Optimierung oder das Verfolgen eines Fehlers auf eine bestimmte Folge von Anweisungen ist für den Programmierer einfach - siehe den Kommentar vor den geschweiften Klammern:
Diese Vorgehensweise ist in bestimmten Kontexten wie Debugging, eingebetteten Geräten oder persönlichem Code hilfreich.
quelle
Ich stimme "ruakh" zu. Wenn Sie eine gute Erklärung der verschiedenen Ebenen des Geltungsbereichs in C wünschen, lesen Sie diesen Beitrag:
Verschiedene Umfangsebenen in der C-Anwendung
Im Allgemeinen ist die Verwendung von "Block scope" hilfreich, wenn Sie nur eine temporäre Variable verwenden möchten, die Sie während der gesamten Lebensdauer des Funktionsaufrufs nicht verfolgen müssen. Darüber hinaus wird es von einigen Benutzern verwendet, sodass Sie denselben Variablennamen an mehreren Stellen verwenden können, obwohl dies im Allgemeinen keine gute Idee ist. z.B:
In diesem speziellen Beispiel habe ich returnValue zweimal definiert, aber da es sich nur um einen Blockbereich handelt, anstatt um einen Funktionsbereich (dh: Funktionsbereich würde beispielsweise returnValue direkt nach int main (void) deklarieren), tue ich dies nicht Erhalten Sie alle Compilerfehler, da jeder Block die deklarierte temporäre Instanz von returnValue nicht kennt.
Ich kann nicht sagen, dass dies im Allgemeinen eine gute Idee ist (dh Sie sollten Variablennamen wahrscheinlich nicht wiederholt von Block zu Block wiederverwenden), aber im Allgemeinen spart dies Zeit und Sie können vermeiden, dass Sie die verwalten müssen Wert von returnValue über die gesamte Funktion.
Beachten Sie abschließend den Umfang der in meinem Codebeispiel verwendeten Variablen:
quelle
Warum also "unnötige" geschweifte Klammern verwenden?
#pragma
oder Definieren von "Abschnitten", die visualisiert werden können)PS Es ist kein schlechter Code; es ist 100% gültig. Es ist also eher eine Frage des (ungewöhnlichen) Geschmacks.
quelle
Nachdem ich den Code in der Bearbeitung angezeigt habe, kann ich sagen, dass die unnötigen Klammern (in der ursprünglichen Codiereransicht) wahrscheinlich zu 100% klar sind, was während des Wenn / Dann passieren wird, obwohl es jetzt nur eine Zeile ist Weitere Zeilen später, und die Klammern garantieren, dass Sie keinen Fehler machen.
Wenn das oben genannte Original war und das Entfernen von "Extras" zu folgenden Ergebnissen führen würde:
dann könnte eine spätere Änderung folgendermaßen aussehen:
und das würde natürlich ein Problem verursachen, da jetzt isInit immer zurückgegeben wird, unabhängig vom if / then.
quelle
Objekte werden automatisch zerstört, wenn sie den Gültigkeitsbereich verlassen ...
quelle
Ein weiteres Anwendungsbeispiel sind UI-bezogene Klassen, insbesondere Qt.
Zum Beispiel haben Sie eine komplizierte Benutzeroberfläche und viele Widgets, von denen jedes seinen eigenen Abstand, sein eigenes Layout usw. hat. Anstatt sie zu benennen, können
space1, space2, spaceBetween, layout1, ...
Sie sich vor nicht beschreibenden Namen für Variablen schützen, die nur in zwei bis drei Zeilen von existieren Code.Nun, einige mögen sagen, dass Sie es in Methoden aufteilen sollten, aber das Erstellen von 40 nicht wiederverwendbaren Methoden sieht nicht in Ordnung aus. Deshalb habe ich beschlossen, nur geschweifte Klammern und Kommentare vor ihnen einzufügen, damit es wie ein logischer Block aussieht. Beispiel:
Ich kann nicht sagen, dass dies die beste Vorgehensweise ist, aber es ist gut für Legacy-Code.
Diese Probleme traten auf, als viele Leute ihre eigenen Komponenten zur Benutzeroberfläche hinzufügten und einige Methoden sehr umfangreich wurden, aber es ist nicht praktikabel, 40 Methoden für die einmalige Verwendung innerhalb der Klasse zu erstellen, die bereits durcheinander geraten sind.
quelle