155 Stimmen

Wie viele und welche Verwendungen gibt es für "const" in C++?

Als Anfänger in der C++-Programmierung gibt es einige Konstrukte, die mir noch sehr undurchsichtig erscheinen, eines davon ist const . Man kann es an so vielen Stellen und mit so vielen verschiedenen Effekten verwenden, dass es für einen Anfänger fast unmöglich ist, lebendig herauszukommen. Wird ein C++-Guru einmal für immer die verschiedenen Verwendungen erklären und ob und/oder warum man sie nicht verwenden sollte?

109voto

Johannes Schaub - litb Punkte 479831

Ich versuche, einige Verwendungen zu sammeln:

Bindung einiger temporärer an reference-to-const, um deren Lebensdauer zu verlängern. Die Referenz kann eine Basis sein - und der Destruktor davon muss nicht virtuell sein - der richtige Destruktor wird trotzdem aufgerufen:

ScopeGuard const& guard = MakeGuard(&cleanUpFunction);

Erläuterung , mit Code:

struct ScopeGuard { 
    ~ScopeGuard() { } // not virtual
};

template<typename T> struct Derived : ScopeGuard { 
    T t; 
    Derived(T t):t(t) { }
    ~Derived() {
        t(); // call function
    }
};

template<typename T> Derived<T> MakeGuard(T t) { return Derived<T>(t); }

Dieser Trick wird in der Dienstprogrammklasse ScopeGuard von Alexandrescu verwendet. Sobald das temporäre Element den Anwendungsbereich verlässt, wird der Destruktor von Derived korrekt aufgerufen. Der obige Code lässt ein paar kleine Details vermissen, aber das ist auch schon das Wichtigste.


Verwenden Sie const, um anderen Methoden mitzuteilen, dass sie den logischen Zustand dieses Objekts nicht verändern werden.

struct SmartPtr {
    int getCopies() const { return mCopiesMade; }
};

const für Copy-on-Write-Klassen verwenden , damit der Compiler Ihnen hilft zu entscheiden, wann Sie kopieren müssen und wann nicht.

struct MyString {
    char * getData() { /* copy: caller might write */ return mData; }
    char const* getData() const { return mData; }
};

Erläuterung : Sie können Daten gemeinsam nutzen, wenn Sie etwas kopieren, solange die Daten des ursprünglichen und des kopierten Objekts gleich bleiben. Sobald eines der Objekte seine Daten ändert, benötigen Sie jedoch zwei Versionen: Eine für das Original und eine für die Kopie. Das heißt, Sie kopieren. in einem schreiben. zu einem der beiden Objekte, so dass beide nun ihre eigene Version haben.

Code verwenden :

int main() {
    string const a = "1234";
    string const b = a;
    // outputs the same address for COW strings
    cout << (void*)&a[0] << ", " << (void*)&b[0];
}

Der obige Ausschnitt gibt auf meinem GCC die gleiche Adresse aus, da die verwendete C++-Bibliothek ein Copy-on-Write implementiert std::string . Beide Strings teilen sich, obwohl sie unterschiedliche Objekte sind, denselben Speicher für ihre Stringdaten. Herstellung von b non-const wird die non-const-Version der operator[] und der GCC wird eine Kopie des Pufferspeichers erstellen, da wir diesen ändern könnten und dies nicht die Daten von a !

int main() {
    string const a = "1234";
    string b = a;
    // outputs different addresses!
    cout << (void*)&a[0] << ", " << (void*)&b[0];
}

Damit der copy-constructor Kopien von const-Objekten und temporären Objekten erstellen kann :

struct MyClass {
    MyClass(MyClass const& that) { /* make copy of that */ }
};

Für die Erstellung von Konstanten, die sich trivialerweise nicht ändern können

double const PI = 3.1415;

Für die Übergabe beliebiger Objekte per Referenz statt per Wert - um die möglicherweise teure oder unmögliche Weitergabe von Werten zu verhindern

void PrintIt(Object const& obj) {
    // ...
}

33voto

JaredPar Punkte 699699

Es gibt eigentlich 2 Hauptverwendungen von const in C++.

Konstante Werte

Wenn ein Wert in Form einer Variablen, eines Mitglieds oder eines Parameters vorliegt, der während seiner Lebensdauer nicht verändert wird (oder werden sollte), sollten Sie ihn als const markieren. Dies hilft, Mutationen des Objekts zu verhindern. In der folgenden Funktion muss ich zum Beispiel die übergebene Instanz Student nicht ändern, also markiere ich sie als const.

void PrintStudent(const Student& student) {
  cout << student.GetName();
}

Warum sollten Sie das tun? Es ist viel einfacher, über einen Algorithmus nachzudenken, wenn man weiß, dass sich die zugrunde liegenden Daten nicht ändern können. "const" ist hilfreich, aber keine Garantie dafür, dass dies erreicht wird.

Es ist offensichtlich, dass das Drucken von Daten in cout nicht viel Nachdenken erfordert :)

Kennzeichnung einer Membermethode als const

Im vorigen Beispiel habe ich Student als const markiert. Aber woher wusste C++, dass der Aufruf der Methode GetName() für Student das Objekt nicht verändern würde? Die Antwort ist, dass die Methode als "const" gekennzeichnet war.

class Student {
  public:
    string GetName() const { ... }
};

Die Kennzeichnung einer Methode als "const" bewirkt 2 Dinge. In erster Linie teilt sie C++ mit, dass diese Methode mein Objekt nicht verändern wird. Zweitens werden nun alle Mitgliedsvariablen so behandelt, als ob sie als "const" gekennzeichnet wären. Dies hilft, verhindert aber nicht, dass Sie die Instanz Ihrer Klasse verändern.

Dies ist ein sehr einfaches Beispiel, das aber hoffentlich Ihre Fragen beantworten kann.

17voto

Steve Folly Punkte 7767

Achten Sie darauf, den Unterschied zwischen diesen 4 Erklärungen zu verstehen:

Die folgenden 2 Deklarationen sind semantisch identisch. Sie können ändern wobei ccp1 und ccp2 zeigen auf etwas, aber man kann das, worauf sie zeigen, nicht ändern.

const char* ccp1;
char const* ccp2;

Außerdem ist der Zeiger eine Konstante, d. h. er muss, um sinnvoll zu sein, so initialisiert werden, dass er auf etwas zeigt. Man kann ihn nicht auf etwas anderes zeigen lassen, aber die Sache, auf die er zeigt kann geändert werden.

char* const cpc = &something_possibly_not_const;

Schließlich kombinieren wir die beiden, so dass der Gegenstand, auf den der Zeiger zeigt, nicht verändert werden kann und der Zeiger auf nichts anderes zeigen kann.

const char* const ccpc = &const_obj;

Die Spiralregel im Uhrzeigersinn kann helfen, eine Erklärung zu entwirren http://c-faq.com/decl/spiral.anderson.html

3voto

JoePerkins Punkte 485

Als kleine Anmerkung, als ich las hier ist es nützlich zu wissen, dass

const gilt für alles, was ist nichts vorhanden ist; in diesem Fall gilt sie für alles, was sich unmittelbar rechts).

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