tutorial scratch programming program how from for beginners c++ compiler-warnings

scratch - Se esperaba "advertencia: variable no utilizada" pero no se genera nada en C++



c++ programming (2)

El primero llama a su constructor definido por el usuario para realizar la inicialización directa. Esto podría tener efectos secundarios. Por lo tanto, se utiliza x1 . (O al menos no se puede determinar fácilmente que no esté en uso).

La segunda copia se construye. Llama a su constructor definido por el usuario para crear un temporal. A continuación, llama al constructor de copia predeterminado para construir x2 . (Vea más abajo en la edición para una discusión más detallada y refinamiento). Por lo tanto, se puede determinar que x2 no se usa porque fue creado por un constructor generado por compilador sin efectos secundarios, y x2 sí no aparece en ninguna otra parte.

El tercero es como el segundo. Se crea un temporal a través de su constructor proporcionado por el usuario, y luego se copia. Se usa el temporal, pero x3 sí no.

Vea la respuesta aceptada a esta pregunta: ¿Existe una diferencia en C ++ entre la inicialización de la copia y la inicialización directa?

EDITAR

Basado en los comentarios, aquí hay una discusión más a fondo.

Primero, hubo el comentario de que la advertencia es engañosa. Esto es quizás algo subjetivo, pero me gustaría señalar que las advertencias de este tipo a menudo se proporcionan solo con el "mejor esfuerzo". Podría ser que algo que no está garantizado en general sea cierto en un caso específico si el compilador solo profundizaría lo suficiente en el código para verificarlo. En algún momento, sin embargo, los desarrolladores del compilador tienen que dibujar una línea. Eso significa que generalmente no puede contar con una advertencia como esta para detectar todos los casos de una variable no utilizada. (Por otro lado, si tienes una variable que se usa y recibes una advertencia, sería un error). Mi opinión personal es que el comportamiento demostrado aquí no es engañoso, pero, nuevamente, veo que hay algunos errores personales. interpretación en hacer tal llamada.

En segundo lugar, @ FrançoisAndrieux señaló que si modificaba el ejemplo dado por el OP para incluir un constructor de copia definido por el usuario, todavía recibe las mismas advertencias. Eso pone en duda mi explicación anterior, que hace referencia al constructor de copia predeterminado. Esto toca un segundo punto de la teoría, que voy a seguir con una respuesta específica para este caso. El punto de la teoría es que, a menos que realmente desee profundizar en el compilador en sí y obtener sus reglas específicas, el problema en cuestión es si el compilador puede saber razonablemente que la variable no está en uso, teniendo en cuenta que puede haber más de una. De esta forma el compilador pudo haber llegado a su conclusión.

Como el ejemplo se publicó originalmente, creo que mi respuesta da una forma en que el complaciente podría haber llegado a su conclusión. Otra forma, que parece ser aplicable tanto a la forma original como a la forma modificada sugerida por el comentario, se basa en la elección de la copia. Hay una extensa discusión de esto aquí: ¿Qué son la optimización de copia y el valor de retorno? El punto clave para la discusión actual es que, específicamente para los constructores de copias , el compilador puede ignorar los efectos secundarios. De hecho, en algunos casos, el compilador debe ignorar la copia. Evidentemente, el compilador aquí está teniendo esto en cuenta, ya sea directa o indirectamente, al emitir la advertencia. Es probable que esto también vaya al punto señalado por el OP de que el código de ensamblaje en los tres casos es el mismo, porque la acción de copia se ha optimizado.

Permítanme ahora intentar anticipar la siguiente pregunta: "Si la copia se elimina, ¿por qué los tres casos no son realmente iguales?" La respuesta aquí, creo, es en qué variable específica no se usa. Se construyen las variables temporales sin nombre en el segundo y tercer caso, no las variables nombradas x2 y x3 . Las variables temporales caen en el mismo patrón que el primer caso en el ejemplo y se "utilizan" (o al menos no se pueden determinar con la suficiente facilidad como para no ser utilizadas). Eso aún deja a x2 y x3 sin usar por cualquier estándar una vez que se optimiza la construcción de copia.

Código de prueba:

struct X { X (int x) {} }; int main() { X x1(0); // nothing! X x2 = 0; // warning: unused variable X x3 = X(0); // warning: unused variable }

Pregunta

¿Por qué no se genera una advertencia para x1 ?

Notas:

  • Estoy compilando con la opción -Wall .

  • Tanto GCC como Clang producen resultados equivalentes.

  • Esas 3 líneas generan las mismas instrucciones del ensamblador (colocadas algunas asm("nop") para mayor claridad):

    nop lea -0x8(%rbp),%rdi mov $0x0,%esi callq 400600 <X::X(int)> nop lea -0x10(%rbp),%rdi mov $0x0,%esi callq 400600 <X::X(int)> nop lea -0x18(%rbp),%rdi mov $0x0,%esi callq 400600 <X::X(int)> nop

  • No sucede con los tipos primitivos (por ejemplo, typedef int X ).

  • Si la razón se refiere al hecho de que puede haber efectos secundarios en el constructor, entonces la pregunta es: ¿por qué recibo las otras dos advertencias?

Editar:

  • Esto no es un duplicado de esta pregunta IMO ya que en este caso el constructor no es trivial .

La respuesta de @Brick sigue. Para diferentes semánticas, puede terminar con el mismo código de objeto final, para probar que intente agregar -fno-elide-constructors a sus banderas , elision es el culpable que lleva al mismo código de objeto, incluso en -O0 .