Bitte deklarieren Sie Ihre Variablen als const

Bitte deklarieren Sie Ihre Variablen als const

Ich muss gestehen, dass ich in den letzten Jahren ein wenig besessen von der Idee war, alle Variablen zu const zu machen . Wann immer ich eine Variable in einem Funktionskörper deklariere, versuche ich zu überlegen, ob ich sie konstant machen kann. Lassen Sie mich erklären, warum ich denke, dass Sie dasselbe tun sollten.

Was ist los?

Was ist falsch am folgenden Code?

int myVariable = 0;

// some code...

myVariable = ComputeFactor(params...);

Gegen:

// some code...

const int myVariable = ComputeFactor(params...);

Im ersten Beispiel ändern wir nur den Wert einer Variablen, und das ist typisch für den Code … nicht wahr?

Lassen Sie uns die Liste der Vorteile des zweiten Ansatzes durchgehen.

Bitte beachten Sie, dass ich mich nur auf Variablen konzentriere, die in Funktionskörpern verwendet werden, nicht auf Parameter von Funktionen oder Klassenmitglieder.

Warum es hilft

Leistung?

Vor einigen Jahren schlug mein Kollege vor, const zu verwenden für Variablen. Obwohl der einzige Grund dafür Optimierung und Leistung waren. Später wurde mir klar, dass es nicht so offensichtlich ist und dass es weitaus wichtigere Gründe für die Verwendung von const gibt .

Tatsächlich kann ein guter C++-Compiler die gleiche Art von Optimierung durchführen, egal ob Sie const verwenden oder nicht. Der Compiler wird ableiten, ob eine Variable geändert oder nur einmal beim Start initialisiert wird. Gibt es hier also einen Leistungsvorteil?

Es ist schwierig, hier die wahren Zahlen zu zeigen. Idealerweise könnten wir ein C++-Projekt (sagen wir mindestens 10k LOC) bekommen und dann const verwenden wann immer möglich, und vergleichen Sie es mit demselben Projekt ohne const .

In einer synthetischen, kleinen Beispielen wie:

string str;
str = "Hello World";

gegen

const string str = "Hello World";

Es kann sogar eine Leistungssteigerung von 30% geben! Zahlen von J.Turner sprechen über „Praktische Leistungspraktiken“. Wie ein Kommentar bemerkte:Der Gewinn kommt nicht von der Konstante selbst, sondern von der Tatsache, dass wir den Wert nicht neu zuweisen.

Wie wir sehen können, gibt es Potenzial, etwas Leistung zu gewinnen, aber ich würde nicht viel über das gesamte Projekt erwarten. Es kommt auf den Kontext an. Vielleicht so etwas wie 1 ... oder 2 % max. Wie immer gilt:Messen, Messen, Messen! :)

Trotzdem, warum nicht das Leben für den Compiler viel einfacher machen und besseren Code haben.

Es scheint also, dass die „Leistung“ nicht der stärkste Grund für die Verwendung von const ist . Lesen Sie weiter für weitaus wichtigere Aspekte:

Variablen werden für ihre Verwendung lokal deklariert

Wenn Sie eine konstante Variable deklarieren möchten, müssen Sie alle erforderlichen Daten zur Verfügung haben. Das bedeutet, dass Sie es nicht einfach am Anfang einer Funktion deklarieren können (wie im alten Standard-C-Weg). Daher besteht eine höhere Wahrscheinlichkeit, dass Variablen ziemlich lokal für ihre tatsächliche Verwendung verwendet werden.

void foo(int param)
{
    const int otherVariable = Compute(param);
    // code...

    // myVar cannot be declared before 'otherVariable'
    const int myVar = param * otherVariable; 
}

Das Deklarieren von Variablen als lokal für ihre Verwendung ist nicht nur eine gute Vorgehensweise, sondern kann auch zu weniger Speicherverbrauch (da möglicherweise nicht alle Variablen zugewiesen werden) und noch sichererem Code führen.

Eindeutige Absicht

Wenn Sie etwas als konstant deklarieren, machen Sie deutlich:„Ich werde den Wert dieser Variablen nicht ändern.“

Eine solche Praxis ist unerlässlich, wenn Sie den Kodex lesen. Zum Beispiel:

int myVar = 0;

// code...

// code...

Wenn Sie so etwas sehen, sind Sie sich nicht sicher, ob myVar wird sich ändern oder nicht. Bei kleinen Funktionen mag das kein Problem sein, aber was ist mit längeren, komplexen Methoden?

Dabei:

const int myVar = ...;

// code...

Mit myVar passiert wenigstens nichts . Sie müssen einen Parameter weniger nachverfolgen.

Clean-Code

Manchmal ist die Initialisierung einer Variablen nicht nur eine einfache Zuweisung. Es können mehrere Zeilen (oder mehr) verwendet werden, um einen richtigen Wert anzugeben. Machen Sie in diesem Fall die Variable const zwingt Sie dazu, diese Initialisierung an einen anderen Ort zu verschieben.

Wie ich in IIFE für ComplexInitialization beschrieben habe, können Sie die Initialisierung in IIFE oder eine andere Methode einschließen. Auf jeden Fall vermeiden Sie Code, der so aussieht:

int myVariable = 0;

// code... 

// complex initialization of 'myVariable'
if (bCondition)
    myVariable = bCond ? computeFunc(inputParam) : 0;
else
    myVariable = inputParam * 2;

// more code of the current function...

Egal, was Sie verwenden, Sie haben am Ende nur einen Ort, an dem die Variable ihren Wert erhält.

Weniger Fehler

Wenn eine Variable const ist Sie können es nicht ändern, daher ist es weniger wahrscheinlich, dass einige unerwünschte Fehler auftreten.

Es können leicht versehentliche Probleme auftreten, wenn es einige lange Funktionen gibt und Variablen dazu neigen, wiederverwendet zu werden in manchen Fällen. Sie ändern den Wert einer Variablen, und es funktioniert für Ihren Fall, aber der alte Fall, in dem es verwendet wurde, funktioniert jetzt nicht mehr. Deklarieren Sie erneut eine Variable als const wird Sie zumindest vor solchen dummen Fehlern schützen. Ganz zu schweigen davon, dass das Debuggen solcher Fehler sehr mühsam sein kann.

Übrigens:Als Beispiel sehen Sie sich bitte diese Blogbeiträge von Andrzej Krzemienski an:More const — lessbugs

Wechsel zu funktionalen Sprachen

Funktionaler Stil ist wahrscheinlich ein Thema, das einen separaten Artikel wert ist, aber im Allgemeinen unveränderliche Objekte zu haben ist eine wesentliche Sache in funktionalen Sprachen.

Unveränderliche Objekte sind von Natur aus threadsicher. Wenn ein Thread diese Art von Objekten verarbeitet, können wir sicher sein, dass keine anderen Threads die Objekte ändern. Viele Datenrennen können vermieden werden. Das eröffnet viele Möglichkeiten, den Algorithmus relativ einfach zu parallelisieren.

Weil andere es sagen

Aus C++ Core Guidelines (Con:Constants and Immutability)

Und

Aus EffectiveC++ von Scott Meyers (Kapitel 3):

Jason Turner:

  • CppCon 2016:„Rich Code for Tiny Computers:A Simple Commodore 64Game in C++17“
  • Praktische Leistungspraktiken

Ausnahmen

‚Eine konstante Variable‘ ist das nicht ein Oxymoron?

Natürlich gibt es Situationen, in denen eine Variable „normal“ sein muss. Tatsächlich könnten Sie argumentieren, dass die meisten Fälle die Notwendigkeit beinhalten, einen Wert zu ändern. Wenn Sie also nicht versuchen, funktionalen Code zu schreiben (der Unveränderlichkeit mag), werden Sie am Ende unzählige Beispiele erhalten, wenn Sie einen Wert (oder nur einen Teil eines Objekts) ändern müssen.

Einfache Beispiele:Berechnen einer Summe eines Arrays, Iteratoren, kleine Funktionen, Ändern von Gesundheitsparametern in GameActor, Setzen eines Teils der GPUpipeline.

Denken Sie jedoch daran, dass die meisten der oben genannten Beispiele auch in eine „unveränderliche“ Version umgeschrieben werden könnten. Beispielsweise können Sie Funktionen höherer Ordnung wie Falten/Reduzieren und Rekursion verwenden, um viele „Standard“-Algorithmen zu implementieren. Aber das geht in den Bereich der funktionalen Sprachen.

Eine Anmerkung: Während ich diesen Artikel schrieb, wurde mir klar, dass ich hier einen Unterschied mache:Variablen vs. größere Objekte. Theoretisch sind das die gleichen, aber aus praktischen Gründen ist es einfacher, const zu verwenden auf kleineren, „atomaren“ Typen. Also versuche ich, const zu verwenden für kleinere Typen:wie Zahlen, Strings, Vector2d usw., aber wenn ich eine große benutzerdefinierte Klasse habe, überspringe ich einfach const und erlauben, seinen Zustand zu ändern (falls erforderlich). Vielleicht in meiner nächsten Iteration meiner „const correctness“ Ich werde versuchen, diese Regel auch auf größere Objekte anzuwenden … also wäre dies ein funktionalerer Programmierstil.

Zusammenfassung

Ich hoffe, nachdem Sie diesen Beitrag gelesen haben, versuchen Sie es zumindest mit const Variablen häufiger. Es geht nicht darum, zu 100 % const zu sein jedes Mal, aber es ist wichtig, die Vorteile dieses Ansatzes zu sehen.

Wie ich beschrieben habe, wird der resultierende Code ausführlicher, expliziter, sauberer (mit wahrscheinlich kleineren Funktionen) und sicherer. Ganz zu schweigen davon, dass Sie zusätzliche Hilfe vom Compiler erhalten.

Haben Sie const Variablen wenn möglich?

Erwähnt Ihre Projektrichtlinie const Korrektheit?