ventajas que español desventajas caracteristicas c++ compiler-warnings

que - ¿Un "nombre de variable;" instrucción de C++ será un no-op en todo momento?



mongodb español (2)

Bueno, no es realmente posible decirlo con un 100% de certeza sin mirar el código fuente del compilador, pero me sorprendería mucho si esto generara algún código en los compiladores modernos.

Al final del día, si está preocupado por alguna instancia en particular, siempre tiene la libertad de ver el código de ensamblaje generado.

En C ++ a veces se definirá una variable, pero no se utilizará. Aquí hay un ejemplo: una función para usar con la macro ATL COM_INTERFACE_ENTRY_FUNC_BLIND :

HRESULT WINAPI blindQuery( void* /*currentObject*/, REFIID iid, void** ppv, DWORD_PTR /*param*/ ) { DEBUG_LOG( __FUNCTION__ ); //DEBUG_LOG macro expands to an empty string in non-debug DEBUG_LOG( iid ); iid; // <<<<<<<----silence compiler warning if( ppv == 0 ) { return E_POINTER; } *ppv = 0; return E_NOINTERFACE; }

En el ejemplo anterior, el parámetro iid se usa con la macro DEBUG_LOG que se expande en una cadena vacía en configuraciones sin depuración. Por lo tanto, comentar o eliminar el nombre de la variable iid en la firma no es una opción. Cuando se compilan configuraciones sin depuración, el compilador genera un C4100: ''iid'' : unreferenced formal parameter advertencia de C4100: ''iid'' : unreferenced formal parameter , para silenciar la advertencia del iid; Se agrega una declaración que se cree que es un no-op.

La pregunta es la siguiente: si tenemos alguna de las siguientes declaraciones:

CSomeType variableName; //or CSomeType& variableName; //or CSomeType* variableName;

Será la siguiente declaración en código C ++:

variableName;

ser un no-op en todo momento independiente de lo que es CSomeType ?


Sí, pero es probable que reciba otra advertencia.

La forma estándar de hacer esto es: (void)iid; .

Muy técnicamente, esto todavía podría cargar iid en un registro y no hacer nada. Por supuesto, eso es extremadamente estúpido en la parte de los compiladores (dudo que alguna vez haga eso, si elimina el compilador), pero es un problema más serio si la expresión que se debe ignorar es algo relacionado con el comportamiento observable, como las llamadas a las funciones IO o Lectura y escritura de variables volatile .

Esto nos lleva a una pregunta interesante: ¿podemos tomar una expresión e ignorarla por completo ?

Es decir, lo que tenemos ahora es esto:

#define USE(x) (void)(x) // use iid in an expression to get rid of warning, but have no observable effect USE(iid); // hm, result of expression is gone but expression is still evaluated USE(std::cout << "hmmm" << std::endl);

Esto está cerca de una solución:

// sizeof doesn''t evaluate the expression #define USE(x) (void)(sizeof(x))

Pero falla con:

void foo(); // oops, cannot take sizeof void USE(foo());

La solución es simplemente:

// use expression as sub-expression, // then make type of full expression int, discard result #define USE(x) (void)(sizeof((x), 0))

Lo que no garantiza ninguna operación.

Edit: Lo anterior de hecho no garantiza ningún efecto, pero publiqué sin probar. Al realizar la prueba, vuelve a generar una advertencia, al menos en MSVC 2010, porque el valor no se usa. Eso no es bueno, es hora de más trucos!

Recordatorio: queremos "usar" una expresión sin evaluarla. ¿Cómo se puede hacer esto? Me gusta esto:

#define USE(x) ((void)(true ? 0 : (x)))

Esto tiene un problema simple como la última vez (peor en realidad), ya que (x) debe ser convertible a int . Esto es, de nuevo, trivial para arreglar

#define USE(x) ((void)(true ? 0 : ((x), 0)))

Y volvimos al mismo tipo de efecto que tuvimos la última vez (ninguno), pero esta vez x se "usa", por lo que no recibimos ninguna advertencia. ¿Bien hecho?

Todavía hay un problema con esta solución (y estuvo presente en la última no solución también, pero pasó desapercibida), y aparece en este ejemplo:

struct foo {}; void operator,(const foo&, int) {} foo f; USE(f); // oops, void isn''t convertible to int!

Es decir, si el tipo de la expresión (x) sobrecarga al operador de coma en algo que no se puede convertir en int , la solución falla. Claro, improbable, pero por el hecho de ir completamente por la borda, podemos arreglarlo con:

#define USE(x) ((void)(true ? 0 : ((x), void(), 0)))

Para asegurarnos de que realmente terminamos con cero. Este truco te lo trajo Johannes .

Además, como se indicó, si lo anterior no fuera suficiente, un compilador lo suficientemente estúpido podría potencialmente "cargar" la expresión 0 (en un registro o algo así), y luego ignorarla.

Creo que es imposible deshacerse de eso, ya que en última instancia necesitamos una expresión que resulte en un tipo de algún tipo que ignorar, pero si alguna vez pienso en eso, lo agregaré.