2010-02-21 17 views
13

¿Cuál es el significado exacto de la frase "como si" en el estándar y cómo funciona cuando un usuario puede modificar partes individuales del comportamiento."como si" en los estándares de lenguaje

La pregunta está relacionada con el estándar C++ cuando se habla de la versión nothrow de operator new. 18.4.1.1/7 lee (el subrayado es mío):

Esta versión nothrow de nuevos equipos de servicio devuelve un puntero obtuvo como si adquirido de la versión normal.

Mi comprensión es que "como si" no requiere una implementación específica, siempre que el comportamiento sea apropiado. Así que si operator new fue implementado como esto (sé que esto no es una aplicación compatible ya que no hay lazo o el uso de la new_handler, pero estoy acortando que centrarse en mi edición):

// NOTE - not fully compliant - for illustration purposes only. 
void *operator new(std::size_t s) 
{ 
    void *p = malloc(s); 
    if (p == 0) 
     throw std::bad_alloc(); 
    return p; 
} 

entonces sería ser legal para escribir la versión nothrow así:

// NOTE - not fully compliant - for illustration purposes only. 
void *operator new(std::size_t s, const std::nothrow_t &nt) 
{ 
    return malloc(s); 
} 

Pero digamos que un programa reemplaza operator new utilizar algún otro asignador. ¿Significa "como si" que el compilador tiene que cambiar automáticamente el comportamiento de la versión de nothrow para usar este otro asignador? ¿Se requiere que el desarrollador reemplace las versiones simple y nothrow?

+0

http://www.gotw.ca/publications/mill15.htm http://www.gotw.ca/publications/mill16.htm –

+2

El último borrador de C++ 0x ha cambiado la redacción: "This nothrow La versión del operador new devuelve un puntero obtenido como si se hubiera adquirido de la versión ordinaria (posiblemente reemplazada) ". Y el comportamiento predeterminado cambió a "Operador de llamadas nuevo (tamaño). Si la llamada retorna normalmente, devuelve el resultado de esa llamada. De lo contrario, devuelve un puntero nulo". –

Respuesta

7

De 1.9 "Ejecución del programa: se requieren

implementaciones conformes a emular (sólo) el comportamiento observable de la máquina abstracta

y en una nota informativa:

Esta disposición se denomina a veces la regla "como si", porque una implementación es libre de ignorar cualquier requisito de esta norma internacional siempre que el resultado sea como si se hubiera obedecido el requisito, en la medida en que pueda determinarse a partir del comportamiento observable del programa. instan ce, una implementación real no necesita evaluar parte de una expresión si puede deducir que su valor no se usa y que no se producen efectos secundarios que afecten el comportamiento observable del programa.

La norma indica específicamente que el requisito "como si" es vinculante en una versión de reemplazo de la versión de nothrow operator new(). Sin embargo, cuando lo leí, ese requisito recaería en el programador anulando operator new(), no el compilador. El otro lado de esta responsabilidad es que creo que el estándar requiere la implementación predeterminada del nothrow operator new() provisto por la biblioteca, debe hacer algo como llamar al lanzamiento new en try/catch y devolver 0 si se captura std::bad_alloc.

Donde la "regla como si" podría entrar para jugar aquí es si el compilador/enlazador/lo que fuera fue lo suficientemente inteligente como para darse cuenta de que cuando se estaba utilizando el lanzamiento predeterminado new(), el valor predeterminado new() el atajo, pero si se anuló el lanzamiento predeterminado new(), el new() que no arroja por defecto debería actuar de manera diferente. Estoy seguro de que esto es técnicamente posible para una implementación (incluso si es probable que no pueda expresarlo en C++ estándar). Me sorprendería si alguna vez hubo una implementación que hizo esto.

Podría estar leyendo demasiado sobre el requisito, pero creo que eso es lo que se puede deducir.

+0

No sé por qué mi primera versión de la respuesta habló sobre el comportamiento requerido de 'operator delete()' ya que su pregunta no preguntó nada sobre eso. Muy poco sueño anoche o algo así. –

+0

acerca de su comentario comenzando con "la otra cara ...", ¿qué más hay en la norma que requiera el 'operador nuevo' noh predeterminado 'para llamar al operador' throwing 'nuevo'? –

+0

No estoy seguro de que haya algo más, lo que estaba tratando de transmitir es que creo que esto evita que el nothrow predeterminado 'new()' tome un atajo y una llamada 'malloc()' (o cualquiera que sea el lanzamiento predeterminado ' new() 'llama directamente. –

2

Si el cambio en el asignador de operator new hace una diferencia observable en el comportamiento de un programa C++ compatible entonces sí, podría requerir un cambio en la aplicación de la ningún tiro versión. Específicamente si operator delete espera solo bloques asignados por el nuevo asignador, entonces el no-throw nuevo debe cambiar.

Mi lectura es que el uso de como si permite una implementación como la suya cuando el usuario no ha anulado la norma operator new. Tan pronto como lo haya hecho, la implementación no debe usar malloc basado en no-throwoperator new y debe llamar explícitamente la versión declarada del usuario o al menos reutilizar la versión declarada por el usuario que un programa conforme no puede decir que no está No se ha implementado la versión no-throw.

+0

Si entiendo correctamente, sugieres que es responsabilidad del compilador garantizar la coherencia entre el operador global nuevo y el nuevo global cuando un usuario solo ha reemplazado uno de ellos. Eso podría ser una gran carga para un compilador, especialmente si tiene que "reutilizar suficiente versión declarada por el usuario". Si esa fuera la intención, tal vez el estándar debería haber especificado que el operador global new se implemente en términos de nuevo y no se puede reemplazar: el usuario solo podría anular el nuevo global. – Dan

+0

el problema es simplemente 'intentar {...}' la llamada al operador ordinario nuevo para evitar que las excepciones se escapen, creo. Sin embargo, eso significaría que lo nuevo ordinario no puede llamar nuevo al nuevo. Extraño. :) –

+0

@Dan: es al revés: el estándar sugiere fuertemente que no se implementa nada nuevo en términos de lanzar nuevos. No creo que haya ninguna intención de que sea de otra manera, aunque si ninguno es reemplazado, entonces está la optimización obvia de nothrow. El "o al menos" de Charles solo señala que tal vez una implementación * podría * salirse de esto con un trabajo de pies elegante. El hecho de que este trabajo de pies elegante es muy difícil no es un defecto en el estándar, ya que esto es algo que una implementación probablemente nunca querría hacer. Simplemente llame al usuario lanzando nuevo. –

0

El desarrollador debe reemplazar las versiones simple y nothrow. Mira esto article en GOTW.

Mi hipótesis es que el estándar impone requisitos a las implementaciones predeterminadas del compilador (y del tiempo de ejecución). Por lo tanto, la frase "como si" cita debe informar al proveedor del compilador que sus implementaciones predeterminadas de esos métodos deben cumplir los criterios especificados. Si un desarrollador decide anular solo una versión del operador nuevo, no creo que sea responsabilidad del compilador hacer que todas las demás versiones del operador sean nuevas. Es responsabilidad del desarrollador. Pero esa es toda mi opinión, no tengo la especificación práctica en este momento para ver lo que dice en el frente.

+1

@Dan - el artículo de GOTW está específicamente hablando de proporcionar un conjunto completo de reemplazos para el ** operador ** específico de clase. Creo que el problema que le preocupa a Herb Sutter es que si anula el operador específico de la clase, ocultará el nuevo operador de nothrow a menos que también lo anule. –

+0

Buen punto, extrañé que preguntabas por los operadores globales nuevos. El último punto antes del resumen puede ser relevante para su pregunta: Sutter sugiere que el nuevo mundo global debería garantizar una semántica consistente con el nuevo estándar. – Dan

Cuestiones relacionadas