2008-09-19 21 views
12

Entiendo que la función no puede cambiar el estado del objeto, pero pensé que leí en alguna parte que el compilador podía suponer que si la función se llamaba con los mismos argumentos, devolvería el mismo valor y por lo tanto podría reutilizar un valor en caché si estuviera disponible. p.ej.¿Cuál es la semántica de una función miembro miembro?

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 puede optimizar la segunda llamada de distancia y, o bien utilizar el valor en un registro o simplemente hacer b = a;

Es esto cierto?

Respuesta

22

const es sobre la semántica del programa y no sobre los detalles de implementación. Debe marcar una función de miembro const cuando no cambie el estado visible del objeto, y debe ser invocable en un objeto que sea él mismo const. Dentro de una función de miembro const en una clase X, el tipo de this es X const *: apunta al objeto constante X. Por lo tanto, todas las variables miembro son efectivamente const dentro de esa función miembro (excepto mutable). Si tiene un objeto const, solo puede llamar al const funciones miembro.

Puede usar mutable para indicar que una variable miembro puede cambiar incluso dentro de una función de miembro const. Esto se usa generalmente para identificar las variables utilizadas para los resultados del almacenamiento en caché, o para las variables que no afectan el estado real observable, como mutexes (aún necesita bloquear el mutex en las funciones de miembro const) o usar 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 de puntero en lugar de hacerlo directamente (incluyendo punteros inteligentes como std::auto_ptr o boost::shared_ptr), el puntero se convierte en const en una función const miembro, pero no al cual apunta a los datos, 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 insertar el código en la función de llamada y optimizar lo que puede ver allí. Esto podría ocasionar que la función efectivamente solo se llame una vez.

La próxima versión del C++ Standard (C++0x) tendrá una nueva palabra clave constexpr. Las funciones etiquetadas constexpr devuelven un valor constante, por lo que los resultados pueden almacenarse en caché. Hay límites sobre lo que puede hacer en dicha función (para que el compilador pueda verificar este hecho).

+0

¡Ah! constexpr era probablemente lo que estaba pensando! Gracias. – Ferruccio

+0

Usted hizo mi día, señor. No sabía todo lo que siempre necesitaba era el 'mutable'. Muchas gracias. – lucastamoios

0

Lo dudo, la función aún podría llamar a una función global que altera el estado del mundo y no viola la const.

2

La palabra clave const en una función miembro marca 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 realizar llamadas a objetos const).

+0

En realidad, si usted tiene un miembro etiquetados mutable, entonces la función const aún puede modificar eso. Esto es principalmente útil para el almacenamiento en caché del último resultado. :-) – 0124816

2

En este contexto, una función de miembro const significa que this se trata como un puntero const también. En términos prácticos, significa que no está permitido modificar el estado de this dentro de una función de miembro const.

Para funciones no-de efectos secundarios (es decir, lo que estamos tratando de lograr), GCC tiene un "atributo de la función" llamada pure (lo usa diciendo __attribute__((pure))): http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

+0

No estoy tratando de lograr funciones sin efecto secundario. Solo quiero entender todas las implicaciones de hacer una función const. – Ferruccio

3

Un método const 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 const. En otras palabras, la palabra clave const NO implica que la función sea uno a uno. Por ejemplo, un método que devuelve la hora actual es un método const pero su valor de retorno cambia entre llamadas.

0

Además de que la función miembro puede modificar datos globales, es posible que la función miembro modifique explícitamente los elementos mutables declarados del objeto en cuestión.

2

La palabra clave mutable en las variables miembro permite que las funciones const alteren el estado del objeto en cuestión.

Y no, no lo hace de caché de datos (al menos no todas las llamadas), ya que el siguiente código es una función const 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 señalado no es const, por lo tanto, la llamada a NextValue en SomeObject puede o no alterar 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 los métodos const. He oído que puede optimizar ciertas cosas, aunque tendré que buscarlo para estar seguro.

0

Corey es correcta, pero hay que tener en cuenta que las variables miembro que están marcadas como mutable puede ser modificado en métodos constantes.

También significa que estas funciones se pueden llamar desde otras funciones const, o a través de otras referencias const.


Edit: Damn, fue vencido por 9 segundos .... 9 !!! :)

+0

Pistola más rápida en el oeste, ¿mucho? :-P –

+0

Oye, mi respuesta fue más de 9 segundos antes que la tuya. : P – KTC

0

los métodos const también pueden modificar locales estáticos. Por ejemplo, la siguiente es perfectamente legal (llamadas y repetidas a bar() devolverá los valores crecientes - no es una caché 0):

class Foo 
{ 
public: 
    int bar() const 
    { 
     static int x = 0; 
     return x++; 
    } 
}; 
Cuestiones relacionadas