2010-12-17 12 views
5

El vector STL plantilla define accessors elemento como tanto const y variantes no constante, por ejemplo:const y no const en contenedores STL

reference operator[](size_type __n) 
    {return *(this->_M_impl._M_start + __n);} 
const_reference operator[](size_type __n) const 
    {return *(this->_M_impl._M_start + __n);} 

¿Cuándo el compilador decide utilizar una versión sobre el otro? El vector en sí no se define como const, ni los elementos están almacenados en él. Así que dado dos funciones:

A f(int i) const 
    { return myVector[i]; } 
A f(int i) 
    { return myVector[i]; } 

Mi entendimiento es que el primero sería llamar a la versión const del operador [] y devolver una constante A. El segundo llama a la versión no constante y devuelve un no constante A?

Para mí, la primera versión de f() parece ser la "correcta" para escribir, ya que la función no está alterando nada, pero tal vez sea sorprendente para la persona que llama que devuelve una const A. Sin duda, si yo quería un const un regresó, yo debería necesitar definir f() como:

const A f(int i) const //Note the extra const at the start 
    { return myVector[i]; } 

¿Qué le diría a todo el que está escribiendo la persona que llama a esperar un const espalda.

¿Entonces la const extra aparece por arte de magia? ¿Y a qué se aplica el const extra si uso un boost :: ptr_vector en lugar de std :: vector? ¿Los datos? El puntero? ¿ambos?

+3

Sería mejor que hicieras una pregunta general sobre 'const'. Y aún mejor, estudia esto en tu libro de texto C++ y probando programas de ejemplo, y luego preguntando sobre cualquier problema concreto. ¿Qué libro de texto estás usando? –

Respuesta

7

Esto aprovecha una parte complicada de las reglas de sobrecarga de funciones. En primer lugar, los calificadores de cv después del paréntesis de cierre de un prototipo de método son como los calificadores cv en los argumentos, pero se aplican al argumento implícito this.En una hipotética C variante ++ en la que tuvo que declarar this, los prototipos serían así:

reference operator[](this_type this, size_type n); 
const_reference operator[](const this_type this, size_type n); 

Por lo tanto, si el objeto que está llamando el método de es const, la segunda sobrecarga es una aproximación más exacta y sera llamado. Si no es así, se llamará a la primera sobrecarga. De modo que obtendrá un const_reference si indexa un contenedor const, y obtendrá un reference si indexa un contenedor que no sea const. El objeto const_reference aplica la naturaleza de solo lectura del contenedor al que apunta.

A veces const_reference es lo mismo que const reference y, a veces no lo es; para los contenedores más complicados, un reference es una clase con código no trivial, y ese código tiene que ser diferente para la variedad de solo lectura. El estándar consistentemente usa const_reference para que los implementadores tengan la libertad de hacerlo cuando lo necesiten.

+0

'const_reference' casi nunca es lo mismo que' const reference', excepto cuando 'value_type' ya es' const'. Si 'reference' es' int & ',' const reference' también sería 'int &', not 'const int &'. – aschepler

1

El const al final de una declaración de función se aplica solo a funciones miembro no estáticas, y significa que *this está const-qualified.

struct A { 
    void f(int i) const; 
    void f(int i); 
}; 

void g(const A& x, A& y) { 
    x.f(); // calls const version 
    y.f(); // calls non-const version 
} 

En contenedores STL, este tipo de sobrecarga se utiliza para determinar si la referencia o iterador devuelto se pueden utilizar para cambiar los elementos del contenedor. No puede cambiar un elemento a través de un contenedor calificado const.

0

Devolver un valor de configuración no tiene sentido, es perfectamente legal construir un nuevo valor a partir de un valor de configuración, por lo que el primer formulario es válido. Piénselo: si quiere copiar desde algún lugar, no importa si no puede escribir allí.

Si devolvió una referencia, el compilador no le permitió devolver un A & en la versión const.

1

En la función:

A f(int i) const 
    { return myVector[i]; } 

devuelve un no constante A. Dado que va a devolver por valor, el valor devuelto por el operador [] (una referencia const) se copia en una nueva A. Estás "perdiendo" la const, pero no importa porque tienes un objeto completamente nuevo. Por el contrario, si su clase tiene este aspecto:

struct B { 
    const A& f(int i) const; 
    A& f(int i); 

private: 
    vector<A> myVector; 
}; 

y le llamaremos f() utilizando una constante B:

const B b; 
const A& a = b.f(); 

su una será una referencia constante.

Cuestiones relacionadas