it-swarm.com.de

Wie viele und welche Verwendungszwecke hat "const" in C ++?

Als C++ - Programmieranfänger gibt es einige Konstrukte, die für mich immer noch sehr undurchsichtig erscheinen. Eines davon ist const. Sie können es an so vielen Orten und mit so vielen verschiedenen Effekten verwenden, dass es für einen Anfänger fast unmöglich ist, lebend herauszukommen. Erklärt ein C++ - Guru einmal für immer die verschiedenen Verwendungszwecke und ob und/oder warum man sie nicht verwendet?

121
tunnuz

Versucht, einige Verwendungen zu sammeln:

Einige werden temporär an reference-to-const gebunden, um ihre Lebensdauer zu verlängern. Die Referenz kann eine Basis sein - und der Destruktor davon muss nicht virtuell sein - der richtige Destruktor heißt immer noch:

ScopeGuard const& guard = MakeGuard(&cleanUpFunction);

Erklärung 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 ScopeGuard-Dienstprogrammklasse von Alexandrescu verwendet. Sobald das temporäre Objekt den Gültigkeitsbereich verlässt, wird der Destruktor von Derived korrekt aufgerufen. In dem obigen Code fehlen einige kleine Details, aber das ist die große Sache.


Verwenden Sie const, um anderen Methoden mitzuteilen, dass der logische Status dieses Objekts nicht geändert wird.

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

Verwenden Sie const für Copy-on-Write-Klassen, damit der Compiler Sie bei der Entscheidung unterstützt, wann und wann Sie nicht kopieren müssen.

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

Erläuterung : Möglicherweise möchten Sie Daten freigeben, wenn Sie etwas kopieren, solange die Daten des ursprünglichen und des kopierten Objekts gleich bleiben. Sobald eines der Objekte Daten ändert, benötigen Sie jedoch zwei Versionen: eine für das Original und eine für die Kopie. Das heißt, Sie kopieren auf ein schreibendes Objekt, so dass Beide haben jetzt ihre eigene Version.

Mit Code :

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

Das obige Snippet gibt die gleiche Adresse auf meinem GCC aus, da die verwendete C++ - Bibliothek ein Copy-on-Write std::string Implementiert. Obwohl beide Zeichenfolgen unterschiedliche Objekte sind, teilen sie sich für ihre Zeichenfolgendaten den gleichen Speicher. Wenn Sie b nicht const setzen, wird die nicht const-Version von operator[] Vorgezogen, und GCC erstellt eine Kopie des Backup-Speicherpuffers, da wir ihn ändern könnten und er die Daten von nicht beeinflussen darf a!

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

Damit der copy-Konstruktor Kopien von const-Objekten und temporären Objekten erstellt:

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

Zum Erstellen von Konstanten, die sich trivial nicht ändern können

double const PI = 3.1415;

Zum Übergeben von beliebigen Objekten als Referenz anstelle von Wert - um möglicherweise teure oder unmögliche Übergabe von Wert zu verhindern

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

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

Konstantenwerte

Wenn ein Wert in Form einer Variablen, eines Elements oder eines Parameters vorliegt, der während seiner Lebensdauer nicht geändert wird (oder werden sollte), müssen Sie ihn als const markieren. Dies hilft, Mutationen am Objekt zu verhindern. Zum Beispiel muss ich in der folgenden Funktion die übergebene Student-Instanz nicht ändern, damit ich sie als const markiere.

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

Warum würdest du das tun? Es ist viel einfacher, über einen Algorithmus nachzudenken, wenn Sie wissen, dass sich die zugrunde liegenden Daten nicht ändern können. "const" hilft, garantiert aber nicht, dass dies erreicht wird.

Offensichtlich erfordert das Drucken von Daten in cout nicht viel Nachdenken :)

Eine Member-Methode als const markieren

Im vorherigen Beispiel habe ich Student als const markiert. Aber woher wusste C++, dass das Aufrufen der GetName () -Methode bei student das Objekt nicht mutieren würde? Die Antwort ist, dass die Methode als const markiert wurde.

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

Das Markieren einer Methode "const" bewirkt zwei Dinge. In erster Linie sagt es C++, dass diese Methode mein Objekt nicht mutieren wird. Die zweite Sache ist, dass alle Mitgliedsvariablen nun so behandelt werden, als ob sie als const markiert wären. Dies hilft, hindert Sie jedoch nicht daran, die Instanz Ihrer Klasse zu ändern.

Dies ist ein sehr einfaches Beispiel, aber es wird hoffentlich helfen, Ihre Fragen zu beantworten.

26
JaredPar

Achten Sie darauf, den Unterschied zwischen diesen 4 Angaben zu verstehen:

Die folgenden 2 Deklarationen sind semantisch identisch. Sie können ändern , wo ccp1 und ccp2 zeigen, aber Sie können nicht ändern, auf was sie zeigen.

const char* ccp1;
char const* ccp2;

Als nächstes ist der Zeiger const, damit er sinnvoll ist, muss er initialisiert werden, um auf etwas zu zeigen. Sie können nicht festlegen, dass es auf etwas anderes verweist, jedoch kann das, was auf verweist, geändert werden.

char* const cpc = &something_possibly_not_const;

Schließlich kombinieren wir die beiden - damit das Objekt, auf das gezeigt wird, nicht geändert werden kann und der Zeiger nicht auf eine andere Stelle zeigen kann.

const char* const ccpc = &const_obj;

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

15
Steve Folly

Als kleine Notiz, wenn ich hier lese, ist es nützlich, das zu bemerken

const gilt für alles, was sich unmittelbar links von ihm befindet (außer wenn nichts vorhanden ist, gilt es für alles, was sich unmittelbar rechts von ihm befindet).

2
JoePerkins