programar - funciones en c++ pdf
¿Por qué los compiladores de C++ no optimizan esta asignación booleana condicional como una asignación incondicional? (3)
Considere la siguiente función:
void func(bool& flag)
{
if(!flag) flag=true;
}
Me parece que si flag tiene un valor booleano válido, esto sería equivalente a establecerlo como
true
incondicional, así:
void func(bool& flag)
{
flag=true;
}
Sin embargo, ni gcc ni clang lo optimizan de esta manera; ambos generan lo siguiente en el nivel de optimización
-O3
:
_Z4funcRb:
.LFB0:
.cfi_startproc
cmp BYTE PTR [rdi], 0
jne .L1
mov BYTE PTR [rdi], 1
.L1:
rep ret
Mi pregunta es: ¿es solo que el código es un caso demasiado especial como para preocuparse por optimizarlo, o hay alguna buena razón por la cual dicha optimización no sería deseada, dado que el
flag
no es una referencia a
volatile
?
Parece que la única razón que podría ser es que la
flag
alguna manera podría tener un valor no
true
o
false
sin un comportamiento indefinido en el momento de leerlo, pero no estoy seguro de si esto es posible.
Aparte de la respuesta de Leon sobre el rendimiento:
Supongamos que la
flag
es
true
.
Supongamos que dos hilos llaman constantemente a
func(flag)
.
La función como está escrita, en ese caso, no almacena nada para
flag
, por lo que debería ser seguro para subprocesos.
Dos hilos acceden a la misma memoria, pero solo para leerla.
Establecer incondicionalmente el
flag
en
true
significa que dos hilos diferentes estarían escribiendo en la misma memoria.
Esto no es seguro, esto no es seguro incluso si los datos que se escriben son idénticos a los datos que ya están allí.
Esto puede afectar negativamente el rendimiento del programa debido a consideraciones de
coherencia de caché
.
Escribir para
flag
cada vez que se llama a
func()
ensuciaría la línea de caché que contiene.
Esto sucederá independientemente del hecho de que el valor que se está escribiendo coincide exactamente con los bits encontrados en la dirección de destino antes de la escritura.
EDITAR
hvd ha proporcionado otra buena razón que impide dicha optimización. Es un argumento más convincente contra la optimización propuesta, ya que puede dar lugar a un comportamiento indefinido, mientras que mi respuesta (original) solo aborda aspectos de rendimiento.
Después de un poco más de reflexión, puedo proponer un ejemplo más de por qué los compiladores deberían estar fuertemente prohibidos, a menos que puedan probar que la transformación es segura para un contexto particular, de introducir la escritura incondicional. Considera este código:
const bool foo = true;
int main()
{
func(const_cast<bool&>(foo));
}
Con una escritura incondicional en
func()
esto definitivamente desencadena un comportamiento indefinido (la escritura en la memoria de solo lectura finalizará el programa, incluso si el efecto de la escritura sería no operativo).
No estoy seguro sobre el comportamiento de C ++ aquí, pero en C la memoria puede cambiar porque si la memoria contiene un valor distinto de cero, que no sea 1, se mantendrá sin cambios con la verificación, pero cambiará a 1 con la verificación.
Pero como no soy muy fluido en C ++, no sé si esta situación es posible.