vector const implica elementos const?

5 minutos de lectura

Lo hace const vector<A> significa que sus elementos son const¿también?

En el código de abajo,

v[0].set (1234); en void g ( const vector<A> & v )
produce el error del compilador

const.cpp:28:3: error: la función miembro ‘set’ no es viable: el argumento ‘este’ tiene el tipo ‘const value_type’ (también conocido como ‘const A’), pero la función no está marcada como const

¿Por qué?

Pero (*v[0]).set(1234); en void h ( const vector<A *> & v )
está bien para el compilador.

¿Cuál es la diferencia entre las versiones?

// ...........................................................
class A {
private:
  int a;
public:
  A (int a_) : a (a_) { }
  int get () const { return a; }
  void set (int a_) { a = a_; }
};

// ...........................................................
void g ( const vector<A> & v ) {
  cout << v[0].get();
  v[0].set (1234); 
} // ()

// ...........................................................
void h ( const vector<A *> & v ) {
  cout << (*v[0]).get();
  (*v[0]).set(1234);
} // ()

avatar de usuario
lisyarus

Sí un const vector proporciona acceso a sus elementos como si fueran constes decir, solo te da const referencias En su segunda función, no son los objetos de tipo A que son constpero punteros a ellos Un puntero siendo const no significa que el objeto al que apunta el puntero sea const. Para declarar un puntero a constante, use el tipo A const *.

  • No, los elementos no son consteso sería vector<const A>. Simplemente no puede obtener una referencia no constante o un puntero hacia ellos.

    –Mike Seymour

    21 de noviembre de 2014 a las 16:18


  • @lisyarus De acuerdo con eso, en la segunda función, los elementos son constantes dos veces. Una vez porque no puede cambiar las celdas de la matriz (el vector es constante), y otra vez porque los elementos mismos (punteros) son constantes por estar en un vector constante. ¿Esto tiene sentido?

    – ciberciudadano1

    21 de noviembre de 2014 a las 16:31

  • @cibercitizen1 No. En la segunda función hno está cambiando el puntero, pero el A apunta el puntero. Y el puntero apunta a un non-const A, así que eso no es un problema. El contenedor solo te da const acceso al puntero guardado en él, por lo que no puede cambiar a lo que apunta.

    – Oguk

    21 de noviembre de 2014 a las 16:41


  • @cibercitizen1 No sigo… “los elementos son constantes dos veces” ? Una variable es constante o no lo es; no existe el concepto de ser doblemente const. Aquí el vector es constante (es decir, no puede agregar/eliminar elementos del vector ni modificar su tamaño). Un vector const devolverá una referencia const a sus elementos a través de la [] operator. En el primer caso, no puede cambiar el valor de un const int&. En el segundo caso, no puede cambiar el valor de una referencia a un puntero constante, pero puede cambiar el valor al que apunta el puntero.

    – Julian

    21 de noviembre de 2014 a las 16:46


  • @MikeSeymour Como nota al margen: vector<const T> no es posible. T no se permite ser const o volatile. Vea también esta respuesta aquí: stackoverflow.com/a/6955332/11346320

    – Zacryon

    8 de julio a las 15:46


avatar de usuario
Serguéi Kalinichenko

la primera versión

v[0].set (1234); 

no compila porque intenta cambiar el primer elemento del vector devuelto por referencia. El compilador piensa que es un cambio porque set(int) no está marcado const.

La segunda versión, por el contrario, sólo lee del vector

(*v[0]).set(1234);

y llamadas set en el resultado de la desreferenciación de una referencia constante a un puntero que recupera.

Cuando usted llama v[0] en un const vector, obtienes un const referencia a A. Cuando el tipo de elemento es un puntero, llamar set en eso está bien. Podrías cambiar el segundo ejemplo a

v[0]->set(1234);

y obtener el mismo resultado que antes. Esto se debe a que obtiene una referencia a un puntero que es constante, pero el elemento al que apunta ese puntero no es constante.

avatar de usuario
Bill Lynch

Entonces, un objeto const solo puede llamar a métodos const. Eso es:

class V {
  public:
    void foo() { ... }        // Can't be called
    void bar() const  { ... } // Can be called
};

Así que echemos un vistazo a un operador de vector[]:

reference       operator[]( size_type pos );
const_reference operator[]( size_type pos ) const;

Entonces, cuando el objeto vector es constante, devolverá un const_reference.

Sobre: (*v[0]).set(1234);

Desglosemos esto:

A * const & ptr = v[0];
A & val = *ptr;
val.set(1234);

Tenga en cuenta que tiene un puntero constante a datos variables. Por lo tanto, no puede cambiar lo que apunta, pero puede cambiar el valor al que apunta el puntero.

  • Upvote para esta respuesta marca explícitamente el elemento como referencia de A * const

    – dragonxlwang

    20 de febrero de 2021 a las 7:45

Sí porque std::vector es un tipo de valor en lugar de un tipo de referencia.

Para simplificar las cosas: Un std::vector considera los valores en su búfer como parte de sí mismo, por lo que cambiarlos significa cambiar el vector. Esto puede ser confuso si solo pensamos en un vector como un puntero a un búfer asignado y el tamaño: no cambiamos estos dos campos cuando cambiamos elementos en el búfer.

Es lo contrario que para los punteros, que son tipos de referencia; si cambia el valor apuntado, no ha cambiado el puntero en sí.

El hecho de que std::vector es un tipo de valor es un elección de diseño – no es algo inherente al lenguaje C++. Así, por ejemplo, la std::span class también es básicamente un par de un puntero y un tamaño, pero un std::span puede ser const mientras aún puede cambiar los elementos señalados. (Existen otras diferencias entre tramos y vectores).

¿Ha sido útil esta solución?