Cuando son exactamente los objetos destruidos en C++, y ¿qué significa eso? ¿Tengo que destruir de forma manual, ya que no hay Recolector de Basura? Cómo hacer excepciones vienen en el juego?


(Nota: Esto pretende ser una puerta de entrada a Desbordamiento de pila en C++ FAQ. Si quieres una crítica a la idea de proporcionar un documento de preguntas frecuentes en este formulario, a continuación la publicación en el meta, la que comenzó todo esto sería el lugar para hacerlo. Las respuestas a esta pregunta son monitoreados en el C++ sala de chat, donde el FAQ idea que comenzó en el primer lugar, entonces, la respuesta es muy probable que se lea por aquellos a quien se le ocurrió la idea).

Los que votaron por cerrar en este tema? No veo ninguna razón. De hecho, su, sin duda un buen FAQ. +1
Pero es este un buena pregunta (que es el criterio a), si no fue hecha por alguien que realmente necesitaba saber la respuesta? Si se pregunta tan común, ¿por qué @Fred necesidad de preguntar a sí mismo sólo por lo que podría proporcionar una respuesta? Mi punto es simplemente que si las reglas del juego, a continuación, «es una buena PREGUNTA» no importa, lo que importa es «¿es este un buen pregunta«, y yo, al menos, el juez esta basado en si es probable que obtener el OP la respuesta que necesita (que es nula en este caso porque el OP sabe la respuesta), y si otros con el mismo problema que se puede encontrar.
Si la camarilla que los puestos de preguntas frecuentes preguntas y conoce las respuestas ya se considera que es una «buena PREGUNTA» es irrelevante
«Si se pregunta por lo común, ¿por qué @Fred necesita preguntarse a sí mismo» – generalmente debido en particular a la gente que no sepa de estas cosas no creo que preguntar, «cuando son objetos destruidos», en su lugar, hacer algunas pregunta específica sobre su código particular, para la cual la respuesta es, «usted necesita entender la vida útil de los objetos». Así que las preguntas específicas que tienen muchos detalles que son irrelevantes para otros cuestionarios sobre el mismo tema. No sé si ese es el caso aquí, pero es para las preguntas más frecuentes preguntas que he utilizado en el pasado para referirse interrogadores.
no hay nada de malo con la auto-responder a las preguntas. De hecho, se anima.

OriginalEl autor fredoverflow | 2011-06-19

2 Comentarios

  1. 75

    En el siguiente texto, voy a distinguir entre ámbito de los objetos, cuyo tiempo de la destrucción es estáticamente determinada por su ámbito envolvente (funciones, bloques, clases, expresiones), y objetos dinámicos, cuya hora exacta de la destrucción es en general no se conoce hasta el tiempo de ejecución.

    Mientras que la destrucción de la semántica de los objetos de la clase está determinada por los destructores, la destrucción de un escalar objeto es siempre un no-op. Específicamente, destruir una variable puntero hace no destruir la pointee.

    Ámbito de los objetos

    automática de objetos

    Automática de objetos (lo que comúnmente se conoce como «variables locales») son destruidas, en orden inverso de su definición, cuando el control de flujo sale del alcance de su definición:

    void some_function()
    {
        Foo a;
        Foo b;
        if (some_condition)
        {
            Foo y;
            Foo z;
        }  <--- z and y are destructed here
    }  <--- b and a are destructed here

    Si se produce una excepción durante la ejecución de una función, todo lo anteriormente construido automática de objetos se destruyan antes de que la excepción se propaga a la persona que llama. Este proceso se llama el desenredo de pila. Durante el desenredo de pila, sin más excepciones que pueden dejar a los destructores de la citada previamente construido automática de objetos. De lo contrario, la función std::terminate se llama.

    Esto lleva a uno de los lineamientos más importantes en C++:

    Destructores nunca debe tirar.

    no local objetos estáticos

    Objetos estáticos definidos en el ámbito de espacio de nombres (lo que comúnmente se conoce como «variables globales») y miembros de datos estáticos son destruidas, en orden inverso de su definición, después de la ejecución de main:

    struct X
    {
        static Foo x;   //this is only a *declaration*, not a *definition*
    };
    
    Foo a;
    Foo b;
    
    int main()
    {
    }  <--- y, x, b and a are destructed here
    
    Foo X::x;           //this is the respective definition
    Foo y;

    Tenga en cuenta que el orden relativo de la construcción (y destrucción) de objetos estáticos definidos en diferentes unidades de traducción es indefinido.

    Si una excepción deja el destructor de un objeto estático, la función std::terminate se llama.

    local objetos estáticos

    Objetos estáticos definidos dentro de las funciones se construyen cuando (y si) el flujo de control pasa a través de su definición por primera vez.1
    Que se destruyan en el orden inverso después de la ejecución de main:

    Foo& get_some_Foo()
    {
        static Foo x;
        return x;
    }
    
    Bar& get_some_Bar()
    {
        static Bar y;
        return y;
    }
    
    int main()
    {
        get_some_Bar().do_something();    //note that get_some_Bar is called *first*
        get_some_Foo().do_something();
    }  <--- x and y are destructed here   //hence y is destructed *last*

    Si una excepción deja el destructor de un objeto estático, la función std::terminate se llama.

    1: Este es un extremadamente modelo simplificado. La inicialización de los detalles de los objetos estáticos son en realidad mucho más complicado.

    clase base subobjetos y miembro de subobjetos

    Cuando el flujo de control deja el destructor del cuerpo de un objeto, su miembro subobjetos (también conocido como «miembros de datos») son destruidos en orden inverso a su definición. Después de eso, su clase base subobjetos se destruyan en el orden inverso de la base de especificador de la lista:

    class Foo : Bar, Baz
    {
        Quux x;
        Quux y;
    
    public:
    
        ~Foo()
        {
        }  <--- y and x are destructed here,
    };          followed by the Baz and Bar base class subobjects

    Si se produce una excepción durante la construcción de uno de Foo‘s subobjetos, entonces todos sus construida anteriormente subobjetos se destruyan antes de que la excepción se propaga. El Foo destructor, por otro lado, se no ser ejecutado, ya que la Foo objeto nunca fue totalmente construido.

    Nota de que el destructor cuerpo no es responsable de destruir los datos propios miembros. Sólo se necesita escribir un destructor si un miembro de datos es un identificador de un recurso que necesita ser liberada cuando el objeto se destruye (como un archivo, un enchufe, una conexión de base de datos, un mutex, o el montón de memoria).

    elementos de la matriz de

    Los elementos de la matriz son destruidos en orden descendente. Si se produce una excepción durante la construcción de la n-ésimo elemento, los elementos de la n-1 a 0 se destruyan antes de que la excepción se propaga.

    objetos temporales

    Un objeto temporal que se construye cuando un prvalue expresión de la clase de tipo que es evaluado. El ejemplo más destacado de un prvalue expresión es la llamada de una función que devuelve un objeto de valor, como T operator+(const T&, const T&). Bajo circunstancias normales, el objeto temporal se destruye cuando la completa expresión que léxicamente contiene el prvalue es completamente evaluado:

    __________________________ full-expression
                  ___________  subexpression
                  _______      subexpression
    some_function(a + " " + b);
                              ^ both temporary objects are destructed here

    La anterior llamada a la función some_function(a + " " + b) es una expresión, porque no es parte de una expresión mayor (lugar, es parte de una expresión-la declaración). Por lo tanto, todos los objetos temporales que se crean durante la evaluación de las subexpresiones que será destruido en el punto y coma. Hay dos de tales objetos temporales: la primera se construye durante la primera adición, y la segunda es que se construyeron durante la segunda adición. El segundo objeto temporal que se destruyan antes de que el primero.

    Si se produce una excepción durante la segunda adición, el primer temporal del objeto se destruye correctamente antes de propagar la excepción.

    Si un local de referencia se inicializa con un prvalue expresión, la vida útil del objeto temporal que se extiende el ámbito de aplicación de los locales de referencia, de modo que no haya una referencia colgante:

    {
        const Foo& r = a + " " + b;
                                  ^ first temporary (a + " ") is destructed here
        //...
    }  <--- second temporary (a + " " + b) is destructed not until here

    Si un prvalue expresión de la no-tipo de clase se evalúa, el resultado es un valor, no un objeto temporal. Sin embargo, un objeto temporal se ser construido si el prvalue se utiliza para inicializar una referencia:

    const int& r = i + j;

    Objetos dinámicos y matrices

    En la siguiente sección, destruir X significa «primera destrucción de X y, a continuación, suelte la memoria subyacente».
    Del mismo modo, crear X significa «primer asignar suficiente memoria y, a continuación, construir X».

    objetos dinámicos

    Un objeto dinámico que se crea a través de p = new Foo se destruye a través de delete p. Si usted se olvida de delete p, usted tiene una pérdida de recursos. Usted nunca debe tratar de hacer uno de los siguientes, ya que todos ellos conducen a un comportamiento indefinido:

    • destruir un objeto dinámico a través de delete[] (nota: los corchetes), free o cualquier otro medio
    • destruir un objeto dinámico varias veces
    • acceso a un objeto dinámico después de que se ha destruido

    Si se produce una excepción durante la construcción de un objeto dinámico, el que subyace a la memoria se libera antes de que la excepción se propaga.
    (El destructor se no ser ejecutado antes de la liberación de memoria, debido a que el objeto nunca fue totalmente construida.)

    matrices dinámicas

    Una matriz dinámica creada a través de p = new Foo[n] se destruye a través de delete[] p (nota: los corchetes). Si usted se olvida de delete[] p, usted tiene una pérdida de recursos. Usted nunca debe tratar de hacer uno de los siguientes, ya que todos ellos conducen a un comportamiento indefinido:

    • destruir una matriz dinámica a través de delete, free o cualquier otro medio
    • destruir una matriz dinámica varias veces
    • de acceso a una matriz dinámica después de que se ha destruido

    Si se produce una excepción durante la construcción de la n-ésimo elemento, los elementos de la n-1 a 0 se destruyan en orden descendente, la que subyace a la memoria es liberada, y la excepción se propaga.

    (Que en general prefieren std::vector<Foo> más de Foo* para matrices dinámicas. Se hace la escritura correcta y robusto código mucho más fácil.)

    de referencia de conteo de punteros inteligentes

    Un objeto dinámico gestionado por varios std::shared_ptr<Foo> objetos es destruido durante la destrucción de la última std::shared_ptr<Foo> objeto involucrado en el intercambio que el objeto dinámico.

    (Que en general prefieren std::shared_ptr<Foo> más de Foo* objetos compartidos. Se hace la escritura correcta y robusto código mucho más fácil.)

    Yo (ojalá) se dirigió a los tres primeros comentarios en mi actualización. Si usted está de acuerdo, por favor remueve para evitar confusiones en el futuro. Con respecto a su cuarto comentario, que otros tipos de objetos dinámicos estás hablando, específicamente? boost::shared_array? Con respecto a su quinto comentario, favor de especificar exactamente el término que debe sustituir por el cual término estándar. Además, yo no soy un experto en el hilo de objetos locales, y estoy reflexionando sobre si esto podría ser demasiado avanzado para este FAQ. Usted puede dar su propia respuesta para ellos, si te gusta. Yo, por una vez, sin duda estaría interesado en la lectura.
    no hay ninguna mención de la orden de destrucción de las variables locales estáticas vs estático variables globales
    Sugiero que describe en detalle el caso de que usted tiene un sistema automático de objetos en un no-de la función void.
    Con respecto a «Que en general prefieren std::vector<Foo> más de Foo* para matrices dinámicas.» – En realidad, la mayoría de las veces std::deque<Foo>es una mejor opción que std::vector<Foo>, pero esta es otra discusión.
    He visto que predicó mucho, pero parece que en la práctica, todo el mundo usa std::vector en lugar de std::deque. Sólo habla por mí mismo aquí, pero me gusta mi memoria contiguas.

    OriginalEl autor fredoverflow

  2. 34

    El destructor de un objeto es llamado automáticamente cuando el objeto de la esperanza de vida termina y es destruido. Usted no debe suelen llamar manualmente.

    Vamos a utilizar este objeto como un ejemplo:

    class Test
    {
        public:
            Test()                           { std::cout << "Created    " << this << "\n";}
            ~Test()                          { std::cout << "Destroyed  " << this << "\n";}
            Test(Test const& rhs)            { std::cout << "Copied     " << this << "\n";}
            Test& operator=(Test const& rhs) { std::cout << "Assigned   " << this << "\n";}
    };

    Hay tres (cuatro en C++11) distintos tipos de objetos en C++ y el tipo del objeto que define los objetos de la vida útil.

    • Almacenamiento estático de la duración de los objetos
    • Automática el tiempo de Almacenamiento de los objetos
    • De Almacenamiento dinámico de la duración de los objetos
    • (En C++11) de Hilo tiempo de Almacenamiento de los objetos

    Almacenamiento estático de la duración de los objetos

    Estos son los más simples y se equiparan a las variables globales. La vida útil de estos objetos es (generalmente) la duración de la aplicación. Estos son (generalmente) construidos antes de la principal se introduce y destruidos (en el orden inverso de ser creado) después de la salida principal.

    Test  global;
    int main()
    {
        std::cout << "Main\n";
    }
    
    > ./a.out
    Created    0x10fbb80b0
    Main
    Destroyed  0x10fbb80b0

    Nota 1: Hay dos tipo de almacenamiento estático duración de objeto.

    estática variables miembro de una clase.

    Estos son para todo el sentido y la finalidad de la misma como variables globales en términos de esperanza de vida.

    variables estáticas dentro de una función.

    Estos son perezosamente creado almacenamiento estático de la duración de los objetos. Se crean en el primer uso (en un hilo que seguro manor para C++11). Al igual que otros estática tiempo de almacenamiento de los objetos que se destruyen cuando la aplicación finaliza.

    Orden de construcción/destrucción

    • El orden de construcción dentro de una unidad de compilación está bien definido y es la misma declaración.
    • El orden de la construcción entre las unidades de compilación es de carácter indefinido.
    • La orden de destrucción es exactamente la inversa de la orden de construcción.

    Automática el tiempo de Almacenamiento de los objetos

    Estos son el tipo más común de los objetos y lo que usted debe utilizar el 99% del tiempo.

    Estos son los tres tipos principales de variables automáticas:

    • variables locales dentro de una función o bloque
    • los miembros de variables dentro de una clase/matriz.
    • variables temporales.

    Variables Locales

    Cuando una función o bloque que se sale de todas las variables declaradas dentro de la función que se/bloque será destruido (en el orden inverso de la creación).

    int main()
    {
         std::cout << "Main() START\n";
         Test   scope1;
         Test   scope2;
         std::cout << "Main Variables Created\n";
    
    
         {
               std::cout << "\nblock 1 Entered\n";
               Test blockScope;
               std::cout << "block 1 about to leave\n";
         } //blockScope is destrpyed here
    
         {
               std::cout << "\nblock 2 Entered\n";
               Test blockScope;
               std::cout << "block 2 about to leave\n";
         } //blockScope is destrpyed here
    
         std::cout << "\nMain() END\n";
    }//All variables from main destroyed here.
    
    > ./a.out
    Main() START
    Created    0x7fff6488d938
    Created    0x7fff6488d930
    Main Variables Created
    
    block 1 Entered
    Created    0x7fff6488d928
    block 1 about to leave
    Destroyed  0x7fff6488d928
    
    block 2 Entered
    Created    0x7fff6488d918
    block 2 about to leave
    Destroyed  0x7fff6488d918
    
    Main() END
    Destroyed  0x7fff6488d930
    Destroyed  0x7fff6488d938

    variables miembro

    La vida útil de un miembro de las variables está enlazado con el objeto que la posee. Cuando los dueños de la vida útil termina todos sus miembros de la esperanza de vida de los extremos. Por lo que necesita para mirar a la vida de un propietario que obedece a las mismas reglas.

    Nota: los Miembros siempre son destruidos antes de que el propietario en el orden inverso de la creación.

    • Por lo tanto para los miembros de la clase que se crean en el orden de la declaración

      y que fue destruido en el orden inverso de la declaración
    • Por lo tanto para los miembros de la matriz que se crean en el orden 0–>parte superior

      y que fue destruido en el orden inverso a inicio–>0

    variables temporales

    Estos son los objetos que son creados como resultado de una expresión, pero no se asigna a una variable. Variables temporales son destruidos al igual que otras variables automáticas. Es sólo que el final de su ámbito de aplicación es el final de la declaración en el que se han creado (esto es usally el ‘;’).

    std::string   data("Text.");
    
    std::cout << (data + 1); //Here we create a temporary object.
                             //Which is a std::string with '1' added to "Text."
                             //This object is streamed to the output
                             //Once the statement has finished it is destroyed.
                             //So the temporary no longer exists after the ';'

    Nota: Hay situaciones donde la vida de un temporal puede ser extendida.

    Pero esto no es relevante para esta discusión sencillos. En el momento de entender que este documento va a ser una segunda naturaleza para usted y antes de que se extiende la vida de un temporal no es algo que usted quiere hacer.

    De Almacenamiento dinámico de la duración de los objetos

    Estos objetos tienen una dinámica de vida útil y se crean con new y destruyó con una llamada a delete.

    int main()
    {
        std::cout << "Main()\n";
        Test*  ptr = new Test();
        delete ptr;
        std::cout << "Main Done\n";
    }
    
    > ./a.out
    Main()
    Created    0x1083008e0
    Destroyed  0x1083008e0
    Main Done

    Para desarrolladores que provienen de la recolección idiomas esto puede parecer extraño (la gestión de la vida útil de su objeto). Pero el problema no es tan malo como parece. No es habitual que en C++ para el uso asignado dinámicamente los objetos directamente. Hemos de gestión de objetos para el control de su vida útil.

    La cosa más cercana a la mayoría de los otros GC recogidos idiomas es la std::shared_ptr. Esto le permitirá mantener un seguimiento del número de usuarios de un objeto creado dinámicamente y cuando todos ellos se han ido llamará delete automáticamente (pienso en esto como una mejor versión normal de un objeto de Java).

    int main()
    {
        std::cout << "Main Start\n";
        std::shared_ptr<Test>  smartPtr(new Test());
        std::cout << "Main End\n";
    } //smartPtr goes out of scope here.
      //As there are no other copies it will automatically call delete on the object
      //it is holding.
    
    > ./a.out
    Main Start
    Created    0x1083008e0
    Main Ended
    Destroyed  0x1083008e0

    Hilo tiempo de Almacenamiento de los objetos

    Estos son nuevos en el lenguaje. Están muy parecida a la de almacenamiento estático de la duración de los objetos. Pero, en vez de vivir la misma vida de la aplicación viven tanto como el hilo de ejecución que están asociados.

    OriginalEl autor Martin York

Dejar respuesta

Please enter your comment!
Please enter your name here