descargar - c++ manual
Cómo asegurarse de que una función solo se llame una vez (5)
Supongamos que tengo una función llamada caller, que llamará a una función llamada callee:
void caller()
{
callee();
}
Ahora se puede llamar a la persona que llama muchas veces en la aplicación, y usted quiere asegurarse de que la llamada se llame solo una vez. (tipo de inicialización perezosa), podría implementarlo usando un indicador:
void caller()
{
static bool bFirst = true;
if(bFirst)
{
callee();
bFirst = false;
}
}
Mi opinión para esto es que necesita más código y necesita una verificación más en cada llamada de la persona que llama.
Una mejor solución para mí es la siguiente: (suponga que el usuario devuelve int)
void caller()
{
static int ret = callee();
}
Pero esto no puede manejar el caso si la persona que llama devuelve void, mi solución está usando la expresión de coma:
void caller()
{
static int ret = (callee(), 1);
}
Pero el problema con esto es que la expresión de coma no se usa mucho y las personas pueden confundirse cuando ven esta línea de código, por lo tanto, causan problemas de mantenimiento.
¿Tiene alguna buena idea para asegurarse de que una función solo se llame una vez?
A salvo de amenazas:
static boost::once_flag flag = BOOST_ONCE_INIT;
boost::call_once([]{callee();}, flag);
Inspirado por algunas personas, creo que usar una macro para envolver la expresión de coma también dejaría clara la intención:
#define CALL_ONCE(func) do {static bool dummy = (func, true);} while(0)
Podría ocultar la función a través de un puntero de función.
static void real_function()
{
//do stuff
function = noop_function;
}
static void noop_function()
{
}
int (*function)(void) = real_function;
Las personas que llaman simplemente llaman a la function
que hará el trabajo la primera vez, y no hacen nada en las llamadas subsiguientes.
Podrías usar esto:
void caller()
{
static class Once { public: Once(){callee();}} Once_;
}
Su primera variante con una bandera booleana bFirst
no es otra cosa que una implementación manual explícita de lo que el compilador hará por usted implícitamente en sus otras variantes.
En otras palabras, en una implementación típica en todas las variantes que pesó hasta ahora, habrá una verificación adicional de una bandera booleana en el código de máquina generado. El rendimiento de todas estas variantes será el mismo (si esa es su preocupación). El código adicional en la primera variante puede parecer menos elegante, pero eso no parece ser un gran problema para mí. (Envolverlo.)
De todos modos, lo que tienes como tu primera variante es básicamente cómo se hace normalmente (hasta que comienzas a lidiar con problemas como el multihilo, etc.)