mit einem Behälterklasse wie std::vector
, gibt es zwei unterschiedliche Konzepte der Konstantheit: die des Behälters (d.h. seine Größe), und dass die Elemente. Es scheint, dass std::vector
diese beiden verwirrt, so dass die folgenden einfachen Code wird nicht kompiliert:const vs nicht konstanten des Behälters und dessen Inhalts
struct A {
A(size_t n) : X(n) {}
int&x(int i) const { return X[i]; } // error: X[i] is non-const.
private:
std::vector<int> X;
};
Beachten Sie, dass, obwohl die Datenelemente (die drei Zeiger auf das & Ende der Daten beginnen und Ende der zugewiesenen Puffers) von std::vector
sindnicht durch einen Aufruf an seinen operator[]
geändert, ist dieses Mitglied const
nicht - ist das nicht ein seltsames Design?
Beachten Sie auch, dass für Roh-Zeigern, diese beiden Konzepte von konstant-ness sind fein säuberlich getrennt, so dass die entsprechenden Roh-Zeiger Code
struct B {
B(size_t n) : X(new int[n]) {}
~B() { delete[] X; }
void resize(size_t n); // non-const
int&x(int i) const { return X[i]; } // fine
private:
int*X;
};
funktioniert gut.
Also, was ist der richtige/empfohlene Weg, um dies zu behandeln, wenn std::vector
(ohne mutable
) verwendet wird?
Ist ein const_cast<>
wie in
int&A::x(int i) const { return const_cast<std::vector<int>&>(X)[i]; }
als akzeptabel erachtet (X
bekannt ist, nicht const
, so dass kein UB hier)?
EDIT nur weitere Verwirrung zu vermeiden: ich die Elemente ändern will, das heißt den Inhalt des Behälters, aber nicht der Behälter selbst (die Größe und/oder Speicherplatz).
Die Daten von 'std :: vector' könnten durch Ihren Aufruf von' operator [] 'geändert werden. Wenn Sie 'A :: X' geschrieben haben, ist 'a.x (1) ++;' vollkommen legal und ändert den Inhalt des Vektors. –
@DavidSchwartz Der * Inhalt * eines Vektors ist nicht seine tatsächliche * Daten * (obwohl Sie sie logischerweise als solche assoziieren können). Wenn Sie 'std :: vector' überprüfen, hat es nur 3 Zeiger als Daten (Anfang und Ende der Daten und Ende des Puffers). Diese bleiben unverändert. – Walter