Recientemente encontré algo similar a las siguientes líneas:
#include <string>
// test if the extension is either .bar or .foo
bool test_extension(const std::string& ext) {
return ext == ".bar" || ".foo";
// it obviously should be
// return ext == ".bar" || ext == ".foo";
}
La función obviamente no hace lo que sugiere el comentario. Pero ese no es el punto aquí. Tenga en cuenta que esto no es un duplicado de ¿Puede usar 2 o más condiciones O en una declaración if? ¡ya que soy completamente consciente de cómo escribirías la función correctamente!
Empecé a preguntarme cómo un compilador podría tratar este fragmento. Mi primera intuición habría sido que esto se compilaría return true;
básicamente. Al enchufar el ejemplo en godbolt , se demostró que ni GCC 9.2 ni clang 9 realizan esta optimización con optimización -O2
.
Sin embargo, cambiando el código a 1
#include <string>
using namespace std::string_literals;
bool test_extension(const std::string& ext) {
return ext == ".bar"s || ".foo";
}
parece hacer el truco ya que el ensamblaje ahora es en esencia:
mov eax, 1
ret
Entonces, mi pregunta principal es: ¿Hay algo que me haya perdido y que no permita que un compilador realice la misma optimización en el primer fragmento?
1 Con ".foo"s
esto ni siquiera se compilaría, ya que el compilador no quiere convertir un std::string
a bool
;-)
Editar
El siguiente fragmento de código también se optimiza "correctamente" para return true;
:
#include <string>
bool test_extension(const std::string& ext) {
return ".foo" || ext == ".bar";
}
operator==(string const&, string const&)
es noexcept
mientras operator==(string const&, char const*)
que no es? No tengo tiempo para profundizar más ahora.
foo || ext == ".bar"
, la llamada se optimiza (ver edición). ¿Eso contradice tu teoría?
a || b
significa "evaluar la expresión b
solo si la expresión a
es false
". Es ortogonal al tiempo de ejecución o al tiempo de compilación. true || foo()
puede optimizarse true
, incluso si foo()
tiene efectos secundarios, porque (sin importar si está optimizado o no) el lado derecho nunca se evalúa. Pero foo() || true
no se puede optimizar a true
menos que el compilador pueda probar que las llamadas foo()
no tienen efectos secundarios observables.
xor eax,eax
aunque sin esa opción llama a la función de comparación de cadenas. No tengo idea de qué hacer con eso.
string::compare(const char*)
tiene algunos efectos secundarios que el compilador no eliminará (queoperator==(string, string)
no tiene)? Parece poco probable, pero el compilador ya determinó que el resultado siempre es verdadero (también lo tienemov eax, 1
ret
) incluso para el primer fragmento.