2010-11-10 12 views
6

Mira, lo que no entiendo es, ¿por qué los programas como los siguientes deberían ser legales?Expresiones sin efectos secundarios en C++

int main() 
{ 
    static const int i = 0; 
    i <i> i; 
} 

Quiero decir, sin duda, nadie en realidad tiene ningún programas actuales que tienen expresiones que no tienen efectos secundarios en ellos, ya que eso sería muy sentido, y sería hacer el análisis & compilar el lenguaje mucho más fácil. Entonces, ¿por qué no solo les deshabilitas? ¿Qué beneficio obtiene realmente el lenguaje al permitir este tipo de sintaxis?

Otro ejemplo es la siguiente:

int main() { 
    static const int i = 0; 
    int x = (i); 
} 

Cuál es el beneficio real de estas declaraciones?

Y cosas como el análisis más irritante. ¿Alguien, alguna vez, declara funciones en el medio de otras funciones? Quiero decir, nos deshicimos de cosas como la declaración implícita de funciones y cosas por el estilo. ¿Por qué no deshacerse de ellos para C++ 0x?

Respuesta

4

que haría el análisis & compilar el lenguaje mucho más fácil

no veo cómo. ¿Por qué es más fácil analizar y compilar i <i> i si está requiere para emitir un diagnóstico, de lo que es analizarlo si se le permite hacer algo que muy bien por favor siempre que el código emitido no tenga efectos secundarios?

El compilador de Java prohíbe el código inalcanzable (a diferencia del código sin efecto), lo cual es una bendición para el programador y requiere un poco de trabajo extra del compilador que lo que un compilador de C++ debe hacer. (análisis básico de dependencia de bloques). ¿Debería C++ prohibir el código inalcanzable? Probablemente no. A pesar de que los compiladores de C++ ciertamente hacen suficiente optimización para identificar bloques básicos inalcanzables, en algunos casos pueden hacer demasiado. ¿Debería ser if (foo) { ...} un bloque ilegible inalcanzable si foo es una constante de tiempo de compilación falsa? ¿Qué pasa si no es una constante en tiempo de compilación, pero el optimizador ha descubierto cómo calcular el valor, si es legal y el compilador tiene que darse cuenta de que la razón por la que lo está eliminando es específico de la implementación, para no dar un error ? Casos más especiales.

en realidad nadie tiene ningún programas actuales que tienen las expresiones sin efectos secundarios en los

Cargas. Por ejemplo, si NDEBUG es verdadero, entonces assert se expande a una expresión vacía sin efecto. Así que eso es aún más casos especiales necesarios en el compilador para permitir algunas expresiones inútiles, pero no otras.

La razón de ser, creo, es que si se ampliara a nada, entonces (a) los compiladores terminarían arrojando advertencias para cosas como if (foo) assert(bar);, y (b) un código como este sería legal en versión pero no en depuración, que es simplemente confuso:

assert(foo) // oops, forgot the semi-colon 
foo.bar(); 

cosas como el análisis sintáctico más irritante

es por eso que se llama "irritante". Es un problema de compatibilidad con versiones anteriores. Si C++ ahora cambió el significado de esos molestos analizadores, el significado del código existente cambiaría. No hay mucho código existente, como usted señala, pero el comité de C++ toma una línea bastante fuerte sobre la compatibilidad con versiones anteriores. Si desea un lenguaje que cambie cada cinco minutos, use Perl ;-)

De todos modos, ya es demasiado tarde. Incluso si tuviéramos una gran idea que el comité de C++ 0x había pasado por alto, por qué alguna característica debería eliminarse o modificarse de manera incompatible, no van a romper nada en el FCD a menos que el FCD sea definitivamente erróneo.

Tenga en cuenta que para todas sus sugerencias, cualquier compilador podría emitir una advertencia para ellos (en realidad, no entiendo cuál es su problema con el segundo ejemplo, pero ciertamente para expresiones inútiles y para analizar molestos en cuerpos de funciones) . Si tiene razón en que nadie lo hace deliberadamente, las advertencias no causarán ningún daño. Si está equivocado, nadie lo hace deliberadamente, su caso declarado para eliminarlos es incorrecto. Las advertencias en los compiladores populares podrían allanar el camino para eliminar una característica, especialmente dado que el estándar está escrito principalmente por compiladores-escritores. El hecho de que no siempre recibamos advertencias sobre estas cosas me sugiere que hay más que eso de lo que piensas.

8

Probablemente porque prohibir haría las especificaciones más complejas, lo que haría que los compiladores fueran más complejos.

+0

Excepto que si el compilador tiene dos formas en que podría analizar una declaración, pero una de ellas es ilegal, entonces sabe que debe ser la otra, lo cual es simple, mientras que si la Norma permite ambas, entonces el compilador debe decidir cuál, que es mucho menos simple. Cuanto menos viables sean los programas, menos lógica necesitará para decidir cuál tiene. – Puppy

+0

Sin embargo, eso no siempre es cierto, ya que los compiladores deben detectar ciertas expresiones inválidas e informar los mensajes de error apropiados. En cualquier caso como usted sugiere, ciertamente no puede asumir que el código es válido. –

+0

+1 para el argumento inteligente (y válido). :-) –

0

¿Por qué no hacer nada se debe tratar como un caso especial? Además, aunque los casos anteriores son fáciles de detectar, uno podría imaginar programas mucho más complicados donde no es tan fácil identificar que no hay efectos secundarios.

0

Como una iteración del estándar de C++, C++ 0x tiene que ser compatible con versiones anteriores. Nadie puede afirmar que las declaraciones que usted escribió no existen en algún software crítico escrito/propiedad de, digamos, NASA o DoD.

De todos modos con respecto a su primer ejemplo, el analizador no puede afirmar que i es una expresión constante estática, y que i <i> i es una expresión inútil - por ejemplo, si i es un tipo de plantilla, i <i> i es una "declaración de variable no válida", no un "cálculo inútil", y aún no es un error de análisis.

+1

Nadie dice que la NASA o DoD tiene que actualizar a C++ 0x. Si les gusta, entonces pueden mantener C++ 03. Las viejas versiones del compilador no desaparecerán mágicamente. – Puppy

0

Tal vez el operador estaba sobrecargado para tener efectos secundarios como cout<<i; Esta es la razón por la que no se pueden eliminar ahora. Por otro lado, C# prohíbe las expresiones de asignación de llamadas o de métodos para usarlas como declaraciones, y creo que esto es algo bueno ya que hace que el código sea más claro y semánticamente correcto. Sin embargo, C# tuvo la oportunidad de prohibir esto desde el principio, lo que no ocurre con C++.

3
  • A veces es conveniente incluir enunciados inútiles en un programa y compilarlos solo para asegurarse de que son legales, p. que los tipos implicados se pueden resolver/emparejar etc.

  • Especialmente en código generado (macros así como mecanismos externos más elaborados, plantillas donde las Políticas o tipos pueden introducir expansiones sin sentido en algunos casos no operativos), teniendo menos especial casos no evitables para evitar cosas más simples

  • Puede haber algún código temporalmente comentado que elimine el uso significativo de una variable, pero podría ser una molestia tener que identificar y comentar de manera similar todas las variables que no se usan en otros lugares .

  • Mientras que en sus ejemplos muestra que las variables son "int" inmediatamente superiores al uso sin sentido, en la práctica los tipos pueden ser mucho más complicados (p.operador <()) y si las operaciones tienen efectos secundarios incluso pueden ser desconocidos para el compilador (por ejemplo, funciones fuera de línea), por lo que cualquier beneficio se limita a casos más simples.

  • C++ necesita una buena razón para romper la compatibilidad hacia atrás (y retenida C).

0

Las expresiones sin efectos secundarios pueden aparecer con más frecuencia de lo que cree en el código de plantilla y macro. Si alguna vez ha declarado std::vector<int>, ha creado una instancia del código de plantilla sin efectos secundarios. std::vector debe destruir todos sus elementos al soltarse, en caso de que haya almacenado una clase para el tipo T. Esto requiere, en algún punto, una declaración similar a ptr->~T(); para invocar el destructor. int no tiene destructor, por lo que la llamada no tiene efectos secundarios y será eliminada por completo por el optimizador. También es probable que esté dentro de un bucle, luego todo el bucle no tiene efectos secundarios, por lo que todo el bucle es eliminado por el optimizador.

De modo que si no permitía expresiones sin efectos secundarios, std::vector<int>no funcionaría, por ejemplo.

Otro caso común es assert(a == b). En las compilaciones de lanzamiento, quiere que desaparezcan estas afirmaciones, pero no puede volver a definirlas como una macro vacía; de lo contrario, declaraciones como if (x) assert(a == b); colocan repentinamente la siguiente instrucción en la declaración if: ¡un desastre! En este caso, assert(x) se puede redefinir como ((void)0), que es una declaración que no tiene efectos secundarios. Ahora la declaración if también funciona correctamente en versiones de lanzamiento; simplemente no hace nada.

Estos son solo dos casos comunes. Hay muchos más que probablemente desconozca. Entonces, aunque las expresiones sin efectos secundarios parecen redundantes, en realidad son funcionalmente importantes. Un optimizador los eliminará por completo, por lo que no habrá impacto en el rendimiento.

Cuestiones relacionadas