¿Cuáles son la semántica de una función miembro constante?
Pregunta
Entiendo que la función no puede cambiar el estado del objeto, pero pensé haber leído en alguna parte que al compilador se le permitió asumir que si la función se llamaba con los mismos argumentos, devolvería el mismo valor y, por lo tanto, podría reutilizarse. un valor almacenado en caché si estaba disponible.p.ej.
class object
{
int get_value(int n) const
{
...
}
...
object x;
int a = x.get_value(1);
...
int b = x.get_value(1);
entonces el compilador podría optimizar la segunda llamada y usar el valor en un registro o simplemente hacer b = a;
¿Es esto cierto?
Solución
const
Se trata de la semántica del programa y no de detalles de implementación.Deberías marcar una función miembro. const
cuando no cambia el estado visible del objeto y debería poder invocarse en un objeto que es en sí mismo const
.Dentro de un const
función miembro en una clase X
, el tipo de this
es X const *
:puntero a constante X
objeto.Por lo tanto, todas las variables miembro son efectivamente const
dentro de esa función miembro (excepto mutable
unos).Si tienes un const
objeto, sólo puedes llamar const
funciones miembro en él.
Puedes usar mutable
para indicar que una variable miembro puede cambiar incluso dentro de un const
función miembro.Esto generalmente se usa para identificar variables utilizadas para almacenar en caché los resultados, o para variables que no afectan el estado observable real, como los mutex (aún es necesario bloquear el mutex en el const
funciones miembro) o utilizar contadores.
class X
{
int data;
mutable boost::mutex m;
public:
void set_data(int i)
{
boost::lock_guard<boost::mutex> lk(m);
data=i;
}
int get_data() const // we want to be able to get the data on a const object
{
boost::lock_guard<boost::mutex> lk(m); // this requires m to be non-const
return data;
}
};
Si mantiene los datos por puntero en lugar de hacerlo directamente (incluidos punteros inteligentes como std::auto_ptr
o boost::shared_ptr
) entonces el puntero se convierte const
en un const
función miembro, pero no los datos apuntados, por lo que puede modificar los datos apuntados.
En cuanto al almacenamiento en caché:en general, el compilador no puede hacer esto porque el estado puede cambiar entre llamadas (especialmente en mi ejemplo de subprocesos múltiples con el mutex).Sin embargo, si la definición está en línea, el compilador puede introducir el código en la función de llamada y optimizar lo que puede ver allí.Esto podría resultar en la función efectivamente solo ser llamado una vez.
La próxima versión del Estándar C++ (C++0x) tendrá una nueva palabra clave constexpr
.Funciones etiquetadas constexpr
Devuelve un valor constante, por lo que los resultados se pueden almacenar en caché.Existen límites sobre lo que puede hacer en dicha función (para que el compilador pueda verificar este hecho).
Otros consejos
La palabra clave mudable en variables miembro permite que funciones constantes alteren el estado del objeto en cuestión.
Y no, no almacena datos en caché (al menos no todas las llamadas), ya que el siguiente código es una función constante válida que cambia con el tiempo:
int something() const { return m_pSomeObject->NextValue(); }
Tenga en cuenta que el puntero puede ser constante, aunque el objeto al que apunta no es constante, por lo tanto, la llamada a NextValue en SomeObject puede alterar o no su propio estado interno.Esto hace que la función algo devuelva valores diferentes cada vez que se llama.
Sin embargo, no puedo responder cómo funciona el compilador con métodos constantes.He oído que puede optimizar ciertas cosas, aunque tendría que buscarlo para estar seguro.
No.
Un método constante es un método que no cambia el estado del objeto (es decir,sus campos), pero no se puede asumir que dada la misma entrada, se determina el valor de retorno de un método constante.En otras palabras, const
La palabra clave NO implica que la función sea uno a uno.Por ejemplo, un método que devuelve la hora actual es un método constante pero su valor de retorno cambia entre llamadas.
La palabra clave const en una función miembro marca el este parámetro como constante.La función aún puede silenciar datos globales (por lo que no se pueden almacenar en caché), pero no datos de objetos (lo que permite llamadas a objetos constantes).
En este contexto, un const
función miembro significa que this
es tratado como un const
puntero también.En términos prácticos, significa que no se le permite modificar el estado de this
dentro de una const
función miembro.
Para funciones sin efectos secundarios (es decir, lo que estás tratando de lograr), GCC tiene un "atributo de función" llamado pure
(lo usas diciendo __attribute__((pure))
): http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
Lo dudo, la función aún podría llamar a una función global que alterara el estado del mundo y no violara la constante.
Además del hecho de que la función miembro puede modificar datos globales, es posible que la función miembro modifique miembros mutables declarados explícitamente del objeto en cuestión.
Corey tiene razón, pero tenga en cuenta que cualquier variable miembro que esté marcada como mudable poder modificarse en funciones miembro constantes.
También significa que estas funciones se pueden llamar desde otras funciones constantes o mediante otras referencias constantes.
Editar:Maldita sea, fui derrotado por 9 segundos....9!!!:)
Los métodos const también pueden modificar locales estáticos.Por ejemplo, lo siguiente es perfectamente legal (y las llamadas repetidas a bar() devolverán valores crecientes, no un 0 almacenado en caché):
class Foo
{
public:
int bar() const
{
static int x = 0;
return x++;
}
};