c++ - parametros - ¿Por qué se puede cambiar el elemento desreferenciado en el vector const de punteros int?
punteros en c ejemplos (4)
No estoy seguro del verdadero significado de const vector<int *>
así que compilé el código siguiente para tener una idea, pero ahora estoy más confundido.
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?
Si me hubiera detenido aquí, habría supuesto que const vector<int *>
es un vector de const int * const
, pero luego probé lo siguiente, lo cual contradice claramente esa suposición.
*(w[0]) += 3; //passed. Value not constant?
*(w[0]) = 20; //passed. Why...
Ahora *(w[0])
por razones desconocidas para mí obviamente trata ++
y +=
y la asignación de manera diferente. Me convencí de que el const vector
solo declara un objeto constante de la clase vector
y que los resultados anteriores podrían depender de la implementación real de la sobrecarga del operador de vector
clase vector
. Pero no puedo entender esto. ¿Alguien puede ayudar a explicar, por favor?
Si es relevante, usé g ++ 4.2 en una Mac.
¿Por qué se puede cambiar el elemento desreferenciado en el vector const de punteros int?
Para const vector<int *>
, el elemento sería const
pointer a non- const
, es decir, int * const
, por lo que puede modificar el objeto apuntado por el puntero, pero no el puntero en sí.
De acuerdo con Precedencia del operador , el operador de incremento postfix tiene una precedencia mayor que el operator*
, entonces *(w[0]) ++;
es equivalente a
* ((w[0]) ++);
El incremento en el puntero se realiza al principio, luego falla. w[0] = &y;
también está tratando de modificar el puntero, por lo que también falla.
Por otro lado, (*w[0]) ++;
(es decir, incremento en la punta) estaría bien. Y las siguientes afirmaciones también están bien, porque ambas están modificando los objetos apuntados por el puntero, no los punteros.
*(w[0]) += 3; //passed.
*(w[0]) = 20; //passed.
Es una cuestión de precedencia del operador .
Cuando lo hace *(w[0]) ++
, intenta modificar el puntero .
Cuando lo hace *(w[0]) += 3
, modifica los datos apuntados por el puntero.
const vector<T>
permite acceder a sus elementos como T const &
( es decir, const T &
). En este caso, T
es int *
, entonces esto es int * const &
, una referencia constante a un puntero que apunta a un int
. El puntero es constante, pero el int no lo es.
El tipo del vector debería haber sido vector<int const *>
( es decir, vector<const int*>
) en cuyo caso se accedería a los elementos a través de int const * const &
.
En pocas palabras, la constness es transitiva con plantillas pero no con punteros. Y si pones punteros en plantillas, obtienes un poco de ambos comportamientos.
w
es un const vector<int *>
. El calificador const
se aplica al vector. Por lo tanto, la función miembro miembro correspondiente se usará para el operator[]
:
const_reference operator[]( size_type pos ) const;
Como el vector está const
qualificado y contiene elementos de tipo int *
(y no const int *
), el tipo de la expresión w[0]
es int * const&
(en lugar de const int *&
). Es decir, es una referencia a un puntero constante a un int
y no a un puntero a una constante int
: la constness se aplica al puntero mismo, no a los datos que se apuntan.
Al hacer *(w[0]) += 3
no está modificando el valor del puntero que devuelve el vector (que es const
), sino el valor al que apunta este puntero . Como este puntero es de tipo int * const
(y no const int *
), puede modificar lo que señala, por lo que funciona. Sin embargo, hacer w[0] = &y
está realizando una asignación en un puntero constante, por lo que no se compila.