Verkaufen Sie mich auf konstante Korrektheit

133

Warum genau wird immer empfohlen, const so oft wie möglich zu verwenden? Es scheint mir, dass die Verwendung von const in C ++ eher ein Schmerz als eine Hilfe sein kann. Aber andererseits komme ich aus der Python-Perspektive dazu: Wenn Sie nicht möchten, dass etwas geändert wird, ändern Sie es nicht. Nachdem dies gesagt wurde, sind hier einige Fragen:

  1. Es scheint, als würde jedes Mal, wenn ich etwas als const markiere, eine Fehlermeldung angezeigt und ich muss irgendwo eine andere Funktion ändern, um auch const zu sein. Dann muss ich irgendwo anders eine andere Funktion ändern . Wird das mit der Erfahrung noch einfacher?

  2. Reichen die Vorteile der Verwendung von const wirklich aus, um die Probleme zu kompensieren? Wenn Sie nicht vorhaben, ein Objekt zu ändern, schreiben Sie doch einfach Code, der es nicht ändert.

Ich sollte beachten, dass ich mich zu diesem Zeitpunkt am meisten auf die Vorteile der Verwendung von const für Korrektheits- und Wartbarkeitszwecke konzentriere, obwohl es auch schön ist, eine Vorstellung von den Auswirkungen auf die Leistung zu haben.

Jason Baker
quelle
1
8 Jahre alte Retrospektive, aber ... Wie wäre es, wenn Sie Ihren Code um das 100-fache beschleunigen (live gesehen)?
Lorro
1
Überprüfen Sie meine Antwort hier (verwandte Frage, ich würde die gleiche Antwort sagen): stackoverflow.com/questions/42310477/… Übrigens : Ich liebeconst
Gines Hidalgo

Antworten:

158

Dies ist der endgültige Artikel zum Thema "Konstante Korrektheit": https://isocpp.org/wiki/faq/const-correctness .

Kurz gesagt, die Verwendung von const ist eine gute Praxis, weil ...

  1. Es schützt Sie vor versehentlichen Änderungen von Variablen, die nicht geändert werden sollen.
  2. Es schützt Sie vor versehentlichen Variablenzuweisungen und
  3. Der Compiler kann es optimieren. Zum Beispiel sind Sie vor geschützt

    if( x = y ) // whoops, meant if( x == y )

Gleichzeitig kann der Compiler effizienteren Code generieren, da er jederzeit genau weiß, wie der Status der Variablen / Funktion sein wird. Wenn Sie engen C ++ - Code schreiben, ist dies gut.

Sie haben insofern Recht, als es schwierig sein kann, die Konstanten-Korrektheit konsistent zu verwenden, aber der Endcode ist präziser und sicherer zu programmieren. Wenn Sie viel C ++ entwickeln, zeigen sich die Vorteile schnell.

Jordan Parmer
quelle
Ich bin immer davon ausgegangen, dass const-Werte frei zwischengespeichert werden können, um viele Parallelitätsprobleme zu vermeiden oder die Geschwindigkeit zu verbessern. Ist das wahr?
Phil H
3
Sicher. constVariablen können die Geschwindigkeit in dem Sinne verbessern, dass der Compiler optimaleren Code generieren kann, da er die volle Absicht und Verwendung der Variablen kennt. Wirst du den Unterschied bemerken? Nun, das ist bei Ihrer Bewerbung umstritten. In Bezug auf die Parallelität sind const-Variablen schreibgeschützt, was bedeutet, dass diese Variablen nicht exklusiv gesperrt werden müssen, da der Wert immer gleich ist.
Jordan Parmer
4
Ab C ++ 11 bedeutet die Standardbibliothek auch const, dass sie threadsicher ist. Die Behandlung Ihres eigenen Codes auf diese Weise erleichtert die Überprüfung auf mögliche Multithreading-Probleme und bietet eine einfache Möglichkeit, API-Garantien für Ihre API-Benutzer bereitzustellen.
PMR
3
Für mich ist einer der größten Vorteile der Konstantenkorrektheit, dass Sie nur durch Betrachten von Funktionsprototypen wissen, wenn Zeiger auf Daten verweisen, die von der Funktion niemals mutiert werden (dh nur Eingaben).
cp.engr
1
Vergiss nicht, dass es logische und physische Konstanz gibt. Jedes enthaltene Aggregatobjekt, das als veränderbar markiert ist, kann sich ändern. Wenn Sie es jedoch als solches markieren, bedeutet dies, dass es nichts mit der logischen Konstanz des enthaltenen Objekts zu tun hat.
Adrian
128

Hier ist ein Teil des Codes mit einem häufigen Fehler, vor dem Sie durch konstante Korrektheit geschützt werden können:

void foo(const int DEFCON)
{
   if (DEFCON = 1)     //< FLAGGED AS COMPILER ERROR! WORLD SAVED!
   {
       fire_missiles();
   }
}
Doug T.
quelle
19
Wir sagen also, dass const notwendig ist, weil ein verdammter Idiot "=" als Zuweisungsoperator in C gewählt hat? ;-)
Steve Jessop
37
Natürlich warnen die meisten modernen Compiler vor Zuweisungen in Bedingungen und wir alle
aktivieren
7
Seien Sie nicht zu hart mit diesem Beispiel: Dies ist das gleiche Beispiel, das von einigen Entwicklern evangelisiert wurde, um uns davon zu überzeugen, if (0 == i) anstelle von if (i == 0) zu verwenden. Endlich kann Dougs Codemuster außerhalb der "if" -Anweisung verwendet werden. Wichtig ist, dass es auf humorvolle Weise einen der Vorteile von const zeigt. + 1.
Paercebal
2
Einige Compiler (und Lints) warnen schon lange davor, und das ist viel nützlicher, um diesen Tippfehler zu erkennen, als const: codepad.org/Nnf5JUXV .
7
@ Roger Sie gehen davon aus, dass wir in einer Welt leben, in der Builds sauber und warnungsfrei sind. Ich habe die Erfahrung gemacht, dass bei vielen Codes Warnungen im Rauschen verloren gehen. Es gibt auch viel Code, der Zuweisungen im if-Ausdruck ausführt, und viele werden argumentieren, dass es sich um einen gültigen, "guten" Stil handelt.
Doug T.
62

Es scheint, als würde jedes Mal, wenn ich etwas als const markiere, eine Fehlermeldung angezeigt und ich muss irgendwo eine andere Funktion ändern, um auch const zu sein. Dann muss ich eine andere Funktion woanders ändern. Wird das mit der Erfahrung noch einfacher?

Aus Erfahrung ist dies ein totaler Mythos. Es passiert, wenn nicht const-korrekt mit const-korrektem Code sitzt, klar. Wenn Sie von Anfang an const-korrekt entwerfen, sollte dies NIEMALS ein Problem sein. Wenn Sie etwas const machen und dann etwas anderes nicht kompatibel ist, sagt Ihnen der Compiler etwas extrem Wichtiges, und Sie sollten sich die Zeit nehmen, um es richtig zu reparieren .

Chris Mayer
quelle
7
Dies hat mir geholfen, so viele Fehler zu vermeiden, bei denen eine const-Funktion eine Nicht-const-Funktion aufrufen wollte, weil ich vergessen habe, dass sie die darunter liegenden Daten ändert.
Mooing Duck
9
Sehr wenige Leute beginnen immer mit sauberen Codebasen. Die meiste Codierung ist die Wartung von Legacy-Code, wobei der zitierte Kommentar ziemlich genau ist. Ich benutze const, wenn ich neue Blattfunktionen schreibe, aber ich frage mich, ob es sich lohnt, Dinge durch ein halbes Dutzend oder ein Dutzend Aufrufebenen von unbekanntem Code zu verfolgen.
Warren Dew
3
Dies ist meiner Erfahrung nach völlig falsch. Verschachtelte Punkttypen verursachen die größten Kopfschmerzen bei solchen Dingen, bei denen Sie mehrere Konstantenquantifizierer in einem einzigen Typ haben können.
Noldorin
4
"Wenn Sie von Anfang an const-korrekt entwerfen", wie oft haben Sie tatsächlich den Luxus, von Anfang an const-korrekt zu erzwingen? Die meisten von uns müssen täglich mit zahlreichen APIs und Bibliotheken umgehen, wo dies nicht der Fall ist und Sie wenig dagegen tun können. „Es scheint , dass jedes Mal , wenn ich etwas Zeichens als const ich einen Fehler ein bekommen“ Also ich mit dem OPs Gefühl zustimmen ...
nyholku
@WarrenDew Das ist ein transitives Argument; Wenn die ursprünglichen Autoren constrichtig verwendet hätten (dh "von Anfang an"), dann gäbe es tatsächlich kein Problem, und genau darum geht es!
Leichtigkeitsrennen im Orbit
31

Es ist nichts für Sie, wenn Sie den Code anfänglich schreiben. Es ist für jemanden (oder Sie einige Monate später), der sich die Methodendeklaration in der Klasse oder Schnittstelle ansieht, um zu sehen, was sie tut. Das Nichtmodifizieren eines Objekts ist eine wichtige Information, die daraus gewonnen werden kann.

Antonio Haley
quelle
1
Das ist nur irgendwie wahr. Const wird auch als Schutz verwendet, um In-Variablen über Schnittstellen usw. zu erzwingen.
Jordan Parmer
Es ist so, aber Sie können dies durch disziplinierte Codierungspraktiken durchsetzen, und das Poster gibt an. Der eigentliche Vorteil ergibt sich daraus, dass sich dies in der API widerspiegelt.
Antonio Haley
2
Genau. Es ist besser, "const int Value = 5;" als haben "int ConstValue = 5;". +1.
Paercebal
6
Der richtige Zeitpunkt, um const-Korrektheit einzufügen, ist, wenn Sie die API anfänglich schreiben. Andernfalls treten beim Nachrüsten Probleme mit der Vergiftung von Konstanten auf (weshalb das Hinzufügen zu altem Code eine völlig andere Sache ist als das Hinzufügen zu neuem Code).
Donal Fellows
@DonalFellows das heißt nicht, dass man später const einfügt. Es heißt, dass Sie die Vorteile später erhalten, wenn Sie den Code mit bereits vorhandener
Konstante
27

Wenn Sie const rigoros verwenden, werden Sie überrascht sein, wie wenig reale Variablen in den meisten Funktionen vorhanden sind. Oft nicht mehr als ein Schleifenzähler. Wenn Ihr Code diesen Punkt erreicht, bekommen Sie ein warmes Gefühl im Inneren ... Validierung durch Kompilierung ... das Reich der funktionalen Programmierung ist in der Nähe ... Sie können es jetzt fast berühren ...

QBziZ
quelle
1
seit C ++ 17 und der constexpr Güte schreibe ich Kompilierzeit-Unit-Tests ... noch näher ...
QBziZ
22

const ist ein Versprechen, das Sie als Entwickler machen und das die Hilfe des Compilers bei der Durchsetzung in Anspruch nimmt.

Meine Gründe, um konstant zu sein:

  • Es teilt den Clients Ihrer Funktion mit, dass Sie die Variable oder das Objekt nicht ändern werden
  • Das Akzeptieren von Argumenten durch const-Referenz gibt Ihnen die Effizienz des Übergebens von Referenzen mit der Sicherheit des Übergebens von Werten.
  • Wenn Sie Ihre Schnittstellen als const korrekt schreiben, können Clients sie verwenden. Wenn Sie Ihre Schnittstelle so schreiben, dass sie nicht konstante Referenzen enthält, müssen Clients, die const verwenden, constness wegwerfen, um mit Ihnen arbeiten zu können. Dies ist besonders ärgerlich, wenn Ihre Schnittstelle nicht-const char * akzeptiert und Ihre Clients std :: strings verwenden, da Sie nur ein const char * von ihnen erhalten können.
  • Wenn Sie const verwenden, wird der Compiler dazu aufgefordert, Sie ehrlich zu halten, damit Sie nicht versehentlich etwas ändern, das sich nicht ändern sollte.
JohnMcG
quelle
20

Meine Philosophie ist, dass Sie, wenn Sie eine wählerische Sprache mit Überprüfungen der Kompilierungszeit verwenden möchten, diese optimal nutzen können. constist eine vom Compiler erzwungene Art zu kommunizieren, was Sie meinen ... es ist besser als Kommentare oder Sauerstoff jemals sein werden. Sie zahlen den Preis, warum nicht den Wert ableiten?

Pat Notz
quelle
20

Das Programmieren von C ++ ohne const ist wie das Fahren ohne Sicherheitsgurt.

Es ist ein Schmerz, den Sicherheitsgurt jedes Mal anzulegen, wenn Sie in das Auto steigen, und 364 von 365 Tagen werden Sie sicher ankommen.

Der einzige Unterschied besteht darin, dass Sie es sofort spüren, wenn Sie Probleme mit Ihrem Auto haben, während Sie bei der Programmierung ohne Konstante möglicherweise zwei Wochen lang suchen müssen, was diesen Absturz verursacht hat, nur um herauszufinden, dass Sie versehentlich ein Funktionsargument durcheinander gebracht haben Sie haben eine nicht konstante Referenz für die Effizienz übergeben.

andreas buykx
quelle
17

Bei der eingebetteten Programmierung kann eine constvernünftige Verwendung beim Deklarieren globaler Datenstrukturen viel RAM sparen, indem die konstanten Daten im ROM oder Flash gespeichert werden, ohne dass sie beim Booten in den RAM kopiert werden.

Bei der täglichen Programmierung können Sie durch constsorgfältiges Verwenden vermeiden, dass Sie Programme schreiben, die abstürzen oder sich unvorhersehbar verhalten, weil sie versuchen, Zeichenfolgenliterale und andere konstante globale Daten zu ändern.

Wenn Sie bei großen Projekten mit anderen Programmierern zusammenarbeiten, constverhindert die ordnungsgemäße Verwendung , dass die anderen Programmierer Sie drosseln.

bk1e
quelle
13

consthilft Ihnen dabei, Code zu isolieren, der Dinge hinter Ihrem Rücken "verändert". In einer Klasse markieren Sie also alle Methoden, die den Status des Objekts nicht ändern, als const. Dies bedeutet, dass constInstanzen dieser Klasse keine Nichtmethoden mehr aufrufen können const. Auf diese Weise wird verhindert, dass Sie versehentlich Funktionen aufrufen, die Ihr Objekt ändern können.

Ist auch constTeil des Überladungsmechanismus, sodass Sie zwei Methoden mit identischen Signaturen verwenden können, jedoch eine mit constund eine ohne. Der eine mit constwird für constReferenzen aufgerufen , und der andere wird für Nichtreferenzen aufgerufen const.

Beispiel:

#include <iostream>

class HelloWorld {
    bool hw_called;

public:
    HelloWorld() : hw_called(false) {}

    void hw() const {
        std::cout << "Hello, world! (const)\n";
        // hw_called = true;  <-- not allowed
    }

    void hw() {
        std::cout << "Hello, world! (non-const)\n";
        hw_called = true;
    }
};

int
main()
{
    HelloWorld hw;
    HelloWorld* phw1(&hw);
    HelloWorld const* phw2(&hw);

    hw.hw();    // calls non-const version
    phw1->hw(); // calls non-const version
    phw2->hw(); // calls const version
    return 0;
}
Chris Jester-Young
quelle
13

Konstante Korrektheit ist eines der Dinge, die wirklich von Anfang an vorhanden sein müssen. Wie Sie festgestellt haben, ist es ein großer Schmerz, es später hinzuzufügen, insbesondere wenn eine große Abhängigkeit zwischen den neuen Funktionen, die Sie hinzufügen, und den alten, nicht konstanten Funktionen besteht, die bereits vorhanden sind.

In vielen Codes, die ich schreibe, hat sich die Mühe wirklich gelohnt, da wir häufig Kompositionen verwenden:

class A { ... }
class B { A m_a; const A& getA() const { return m_a; } };

Wenn wir keine Konstantenkorrektheit hätten, müssten Sie komplexe Objekte nach Wert zurückgeben, um sich zu vergewissern, dass niemand den internen Zustand der Klasse B hinter Ihrem Rücken manipuliert.

Kurz gesagt, Konstanzkorrektheit ist ein defensiver Programmiermechanismus, um sich vor Schmerzen zu schützen.

Peter Kovacs
quelle
7

Angenommen, Sie haben eine Variable in Python. Sie wissen , dass Sie nicht soll es ändern. Was ist, wenn Sie es versehentlich tun?

Mit C ++ können Sie sich davor schützen, versehentlich etwas zu tun, was Sie eigentlich gar nicht hätten tun sollen. Technisch kann man es sowieso umgehen, aber man muss zusätzliche Arbeit investieren, um sich selbst zu erschießen.

Greg Rogers
quelle
4

Es gibt einen schönen Artikel hier etwa const in C ++. Es ist eine ziemlich direkte Meinung, aber ich hoffe, es hilft einigen.

Ólafur Waage
quelle
3

Wenn Sie das Schlüsselwort "const" verwenden, geben Sie eine andere Schnittstelle für Ihre Klassen an. Es gibt eine Schnittstelle, die alle Methoden enthält, und eine Schnittstelle, die nur die const-Methoden enthält. Auf diese Weise können Sie natürlich den Zugriff auf einige Dinge einschränken, die nicht geändert werden sollen.

Ja, mit der Zeit wird es einfacher.

Wesley Tarle
quelle
2

Ich mag konstante Korrektheit ... theoretisch. Jedes Mal, wenn ich versucht habe, es in der Praxis rigoros anzuwenden, ist es irgendwann zusammengebrochen und const_cast macht sich langsam daran, den Code hässlich zu machen.

Vielleicht sind es nur die Designmuster, die ich verwende, aber const ist immer ein zu breiter Pinsel.

Stellen Sie sich zum Beispiel ein einfaches Datenbankmodul vor ... es enthält Schemaobjekte, Tabellen, Felder usw. Ein Benutzer verfügt möglicherweise über einen 'const Table'-Zeiger, der bedeutet, dass er das Tabellenschema selbst nicht ändern darf ... aber was ist mit der Manipulation? die mit der Tabelle verknüpften Daten? Wenn die Insert () -Methode als const markiert ist, muss sie intern die const-ness wegwerfen, um die Datenbank tatsächlich zu manipulieren. Wenn es nicht als const markiert ist, schützt es nicht vor dem Aufruf der AddField-Methode.

Vielleicht besteht die Antwort darin, die Klasse basierend auf den Konstanzanforderungen aufzuteilen, aber das erschwert das Design tendenziell mehr, als ich es mir zum Vorteil wünschen würde.

Rob Walker
quelle
Ich denke, Ihr Beispiel ist ein Fall von Überbeanspruchung von const, aber vergessen Sie nicht den veränderlichen Modifikator, der auf Instanzvariablen angewendet werden kann, um die Konstanz zu entfernen.
Zooba
2
Wann würde eine Insert () - Funktion jemals als const markiert werden, wenn sie nicht falsch benannt ist? Durch das Hinzufügen von Elementen wird normalerweise das Element geändert, zu dem Sie es hinzugefügt haben, was bedeutet, dass es nicht const ist. Was Sie wirklich wollten, war ein TableWithConstSchema.
Greg Rogers
Ich könnte eine weitere Klasse hinzufügen, aber ich möchte die API nicht nur aus Gründen der Konstantenkorrektheit unnötig komplex machen.
Rob Walker
1

Sie können dem Compiler auch Hinweise mit const geben .... gemäß dem folgenden Code

#include <string>

void f(const std::string& s)
{

}
void x( std::string& x)
{
}
void main()
{
    f("blah");
    x("blah");   // won't compile...
}
Keith Nicholas
quelle