2017-09-08 1 views
29

Ich bin mir nicht sicher die wahre Bedeutung vonso kompilierte ich den Code unten, um eine Idee zu bekommen, aber bin jetzt mehr verwirrt.Warum ist das dereferenzierte Element im const-Vektor von int-Zeigern veränderbar?

vector<int *> v; 
int x = 1, y = 2; 
v.push_back(&x); 
v.push_back(&y); 

const vector<int *> w = v; 
w[0] = &y; //failed. Element is a constant pointer? 
*(w[0]) ++; //failed. Element pointer references to constant value? 

Wenn ich hier aufgehört hätte, hätte ich angenommen, dass const vector<int *> ist ein Vektor von const int * const, aber dann habe ich versucht, die folgenden, die eindeutig diese Annahme widerlegt.

*(w[0]) += 3; //passed. Value not constant? 
*(w[0]) = 20; //passed. Why... 

Jetzt *(w[0]) für Grund mir unbekannt behandelt offensichtlich ++ und += und anders Zuordnung. Ich habe mich davon überzeugt, dass const vector nur ein konstantes Objekt der Klasse vector deklariert und dass die obigen Ergebnisse von der tatsächlichen Implementierung der Operatorüberlastung der Klasse vector abhängen. Aber ich kann meinen Kopf nicht darum drehen. Kann mir bitte jemand erklären helfen?

Wenn es relevant ist, habe ich g ++ 4.2 auf einem Mac verwendet.

+1

Sie könnten dies interessant finden: Ändern Sie den Beitrag zu Pre-Inkrement und sehen, was im zweiten Fehler Beispiel passiert. '++ * (w [0]);'. – WhozCraig

+1

Ich denke, eine große Quelle der Verwirrung ist das Schreiben von '* (w [0]) ++;' anstelle von '(* w [0]) ++;' (was ich denke, war wahrscheinlich das beabsichtigte Ergebnis). Die Priorität für den Operator kann manchmal etwas schwierig sein. – Kat

Antwort

33

Warum ist das dereferenzierte Element im const-Vektor von int-Zeigern veränderbar?

Für const vector<int *> würde das Element const Zeiger seine const an nicht, das heißt int * const, so dass Sie das Objekt durch den Zeiger gezeigt ändern können, aber nicht der Zeiger selbst.

Nach Operator Precedence, Postfix Inkrementoperator höhere Priorität hat als operator*, so ist *(w[0]) ++; entspricht

* ((w[0]) ++); 

Das Inkrement auf dem Zeiger auf den ersten durchgeführt wird, dann scheitert es. w[0] = &y; versucht auch, den Zeiger zu ändern, so dass es auch fehlschlägt.

Auf der anderen Seite wäre (*w[0]) ++; (d. H. Inkrementieren auf den Pointee) in Ordnung. Und die folgenden Aussagen sind auch in Ordnung, weil sie beide die Objekte verändern, auf die der Zeiger zeigt, nicht die Zeiger.

*(w[0]) += 3; //passed. 
*(w[0]) = 20; //passed. 
9

Es ist eine Frage von operator precedence.

Wenn Sie *(w[0]) ++ tun, versuchen Sie, den Zeiger zu ändern.

Wenn Sie *(w[0]) += 3 tun, ändern Sie die Daten, auf die der Zeiger zeigt.

5

w ist ein const vector<int *>. Der constQualifier wird auf den Vektor angewendet. Daher wird die entsprechende const Elementfunktion für den operator[] verwendet werden:

const_reference operator[](size_type pos) const;

Da der Vektor const, Qualifizierte und enthält Elemente vom Typ int * (und nicht const int *) ist, die Art des Ausdrucks w[0] ist int * const& (statt const int *&).Das heißt, es ist ein Bezug auf einen konstanten Zeiger auf ein int und kein Bezug auf einen Zeiger auf einen konstanten int: die Konstantheit wird angewandt auf die der Zeiger selbst, nicht auf die Daten darauf zu werden.

Dadurch *(w[0]) += 3 Sie nicht den Wert des Zeigers Modifizieren der Vektor zurückgibt (die const ist), aber der Wert dieser Zeiger auf zeigt. Da dieser Zeiger vom Typ int * const (und nicht const int *) ist, können Sie ändern, worauf es hinweist, damit es funktioniert. Das Ausführen von w[0] = &y führt jedoch eine Zuweisung auf einem konstanten Zeiger durch, so dass es nicht kompiliert.

0

const vector<T> können Sie ihre Elemente als T const & Zugriff (heißtconst T &). In diesem Fall ist Tint *, also ist dies int * const &, eine konstante Referenz auf einen Zeiger, der auf einen int zeigt. Der Zeiger ist konstant, aber der Int ist nicht.

Die Art des Vektors würde via int const * const & zugegriffen würden die Elemente in diesem Fall erforderlich sind vector<int const *> (d.h.vector<const int*>) sein.

Die untere Zeile, constness ist transitiv mit Vorlagen, aber nicht mit Zeigern. Und wenn Sie Zeiger in Vorlagen setzen, erhalten Sie ein bisschen von beiden Verhaltensweisen.

Verwandte Themen