2011-01-22 11 views
12

C99 ofrece la función _Exit, que sale "inmediatamente", aunque hace puede cerrar los descriptores de archivo. Unix/POSIX extiende este comportamiento ordenando el cierre de todos los archivos fd sin enrojecimiento (y ofrece el sinónimo _exit).¿Cómo se comportará _Exit en un programa C++?

¿Llamarán estas funciones a los destructores para objetos static cuando se llaman desde un programa C++? ¿El estándar C++ ofrece alguna garantía sobre _Exit?

(Inspirado por this question; de repente me preguntó lo que sucede en el típico fork-exec - _exit idioma en C++.)

+0

No creo que su "fork? Exec: _exit" capture exactamente cómo se usan normalmente. Sería más como: "(fork == 0)?/* Child */(exec, _exit):/* parent */(continue, wait)" – nobar

+1

@nobar: Intenté darle un nombre tan corto al idioma como sea posible. Temía que pareciera que el código real incitaba a las personas a comenzar a comentar (como "olvidaste buscar errores"). –

+0

Sí, habría hecho esos comentarios. Es una broma :) No, mi problema es que parece el código real (usando el operador "?:"), Y dado que es incorrecto, me causó cierta confusión. – nobar

Respuesta

10

Simplemente no existe en C++ estándar, por lo que no hay garantías.

Es es previsto para su inclusión en C++ 0x. Que especifica (§18.5):

La función _exit (int status) tiene comportamiento adicional en esta Norma Internacional :

- El programa se termina sin ejecutar destructores de objetos de automática, hilo , o almacenamiento estático duración y sin las funciones de llamada pasadas a atexit() (3.6.3).

Seguimiento:

ISO aprobó C++ 0x el 12 de agosto de 2011.

+4

Pero 'std :: exit()' existe y garantiza la limpieza de objetos globales y estáticos. [3.6.3/1] – wilhelmtell

1

Hay un interesante análisis here en relación con la concurrencia y destrucción objeto. Por lo que sé, los destructores no serán llamados. No hay nada al respecto en el estándar actual.

11

En primer lugar, ninguna forma de salida de programa llamará automáticamente a destructores para objetos de montón (implícitos en ISO/IEC 14882: 1998 (E) 12.4.10).

Llamar a exit() no llamará a los destructores para los objetos con duración automática, ya que no regresa a través de sus ámbitos adjuntos (3.6.1.4). Sin embargo, los destructores para objetos estáticos se llamarán, en orden inverso de construcción (18.3.8).

Llamando abort() no llama a ningún destructores para ningún tipo de objeto, ni llama a atexit() funciones registradas (18.3.3). La copia estándar de C++ que tengo aquí está un poco anticuada y no menciona _exit o _Exit directamente, pero me imagino que, si está presente, deberían comportarse igual, es decir, no llamar a ningún destructor. En particular, en el estándar C99, _Exit() omite controladores atexit (se define la implementación si los búferes de flujo se vacían, los flujos abiertos se cierran o los archivos temporales se eliminan).

nota además que abort() puede ser cancelada por la captura de la señal SIGABRT (ISO/IEC 9899: 1999 (E) 7.20.4.1.2 - Sólo tengo C99 aquí, pero espero que sería lo mismo en la versión de referencia de C++) _Exit() no puede.

En una nota más práctica, en la mayoría de las implementaciones de UNIX de abort() y _exit(), abort() plantea una SIGABRT mientras _exit() simplemente llama a una llamada de sistema operativo para terminar el proceso de inmediato. Esto significa que las principales diferencias son:

  • Se puede especificar un código de salida de _exit()
  • abort() puede quedar atrapado por un manejador de señales
  • Dependiendo de la configuración del sistema, sistema operativo, y ulimits, abort() puede dar lugar a un volcado de memoria o similares

En un patrón fork()/exec(), _exit() probablemente sería preferible, para evitar la posibilidad de volcado de memoria.

+0

§3.6.1.4 no dice nada acerca de _Exit o de una familia "exit()". Habla de 'std :: exit'. Nada más y nada menos. –

+0

@Matthew, ¿estamos buscando la misma revisión de la norma? Estoy mirando la edición de 1998, y esa entrada comienza con "Llamar a la función' void exit (int); 'declarada en' '(18.3) ..." – bdonlan

+0

Estoy viendo n1905, que se basa en C++ 03. Pero "void exit (int); declarada en " es 'std :: exit', por lo que el significado parece ser el mismo. –

0

Hice una prueba rápida con gcc en Mac OS y mis destructores no fueron llamados.

struct A 
{ 
    ~A() 
    { 
     puts("A::~A"); 
    } 
}; 

A globalA; 

int main() 
{ 
    A localA; 
    _exit(0); // or _Exit(0) 
    return 0; 
} 

exit(0) por el contrario llamaglobalA 's destructor.

3

Técnicamente, _Exit no está definido por el estándar C++, por lo que ni siquiera puede llamarlo desde un programa C++ 100% portátil. El estándar C++ 03 incorpora por referencia el estándar C89 (también conocido como C90 o ANSI C), mientras que _Exit solo se define en el estándar C99 más nuevo. No estoy seguro de qué versión de C incorpora el próximo estándar C++ 0x, pero supongo que está basado en C99.

En cualquier caso, sin embargo, aquí están las cláusulas pertinentes de los estándares del lenguaje relevantes:

_Exit no está garantizada para cerrar los descriptores de fichero. De C99 §7.20.4.4/2 (énfasis mío):

La función _Exit causa la terminación programa normal a ocurrir y control para ser devuelto al ambiente de acogida. No se invocan funciones registradas por la función atexit ni controladores de señal registrados por la función signal. El estado devuelto al entorno de host se determina de la misma manera que para la función exit (7.20.4.3). Si las transmisiones abiertas con datos almacenados en el búfer no escritos se limpian, las transmisiones abiertas se cierran o los archivos temporales se eliminan están definidos por la implementación.

Recordemos que definido por la implementación significa que la aplicación (es decir, la cadena de herramientas del compilador y entorno de tiempo de ejecución) se puede optar por hacer lo que quiera, pero se debe documentar lo que hace.

De C++ 03 §3.6.3/1:

Destructors (12.4) para los objetos inicializados de duración de almacenamiento estático (declarado en ámbito de bloque o al alcance de espacio de nombres) son llamados como resultado de volver desde main y como resultado de llamar al exit (18.3). Estos objetos se destruyen en el orden inverso de la finalización de su constructor o de la finalización de su inicialización dinámica.Si un objeto se inicializa estáticamente, el objeto se destruye en el mismo orden que si el objeto se hubiera inicializado dinámicamente. Para un objeto de matriz o tipo de clase, todos los subobjetos de ese objeto se destruyen antes de que se destruya cualquier objeto local con duración de almacenamiento estático inicializada durante la construcción de los subobjetos.

§3.6.3/4:

Llamar a la función

        void abort();

declarado en <cstdlib> termina el programa sin ejecutar los destructores de objetos de automático o estático duración de almacenamiento y sin llamar a las funciones pasadas al atexit().

la práctica, en la mayoría de las implementaciones, los destructores de objetos globales se implementan a través de atexit, así que lo que se ve es que _Exit no llamará a los destructores de objetos globales, aunque este comportamiento no está garantizada (ya _Exit y C++ no son garantizado que ambos existen en el mismo idioma).

+0

Thinko on Mi parte: los descriptores de archivos tampoco existen en C99. +1. –

+0

'Técnicamente, _Salir no está definido por el estándar C++' Sí lo es;) –

1

La llamada de destructores estáticos se define en términos de atexit. _exit (o _Exit) se define para no ejecutar controladores atexit. Por lo tanto, ninguna implementación debe invocar a los destructores estáticos.

Los destructores automáticos ni siquiera son llamados cuando se llama a exit().

De modo que cualquier definición correcta de _Exit semántica para C++ no ejecutaría destructores.

2

Tenga en cuenta que mientras que C++ no especifica _Exit y C99 deja definido por la implementación si se vuelca tampones, POSIX requiere que no tampones flush (ya que esto romper el uso principal de _exit/_Exit, es decir, el manejo de fracaso de execve después de fork). Como POSIX no se alinea con los estándares de C++ ni los difiere en nada, creo que es muy poco probable que una versión futura del estándar de C++ intente cambiar nada de esto. Probablemente dejará _Exit sin especificar o especificará que está definido por la implementación.

+0

Esto contradice la respuesta de @Matthew Flaschen de que C++ 0x está alineado con C99 en el asunto de' _Exit', como POSIX ... –

+1

No es contradictorio. C99 lo deja definido por la implementación. El objetivo de POSIX es definir requisitos adicionales sobre C99 que un sistema también debe cumplir para cumplir con POSIX. –

2

C++ 0x define una nueva función llamada std::quick_exit que finaliza un proceso sin llamar a ningún destructores. Acabo de comprobar, g ++ - 4.4.5 ya lo proporciona.

0

fork(), exec() y _exit() son definidos por POSIX y son anteriores a C99 de _Exit() por muchos años. Los programas que usan fork/exec/_exit no son portátiles para todos los sistemas que admiten C++.

Con respecto a _exit() específicamente, es una llamada al sistema operativo que (en POSIX) cerrará los archivos y terminará el proceso directamente (pero no necesariamente rápidamente). Esto omitiría cualquier mecanismo de C++ para invocar destructores.

Incluso con _Exit() o similar proporcionado por C++ 0x, dudo que haya muchas razones para usarlo junto con el tenedor. Es probable que solo proporcione una portabilidad más amplia para una "salida rápida" en otros contextos.Esa funcionalidad ya está cubierta por _exit() si está utilizando la API POSIX.

La terminación del programa se trata en la sección C++ 2003 [3.6.3]. Dice que los objetos estáticos se destruyen implícitamente cuando devuelve main() y cuando se llama a exit(). También dice que tales objetos NO se destruyen cuando se llama al abort(). _exit() no se trata en el estándar C++ 2003, pero el hecho de que está destinado a eludir la limpieza específica del idioma se describe en la documentación de POSIX. Ese efecto se confirma por lo que se establece y por lo que NO se establece en el estándar de C++.

Cuestiones relacionadas