destructor of class c++



Destrucción del valor de retorno en la excepción del destructor. (1)

Tengo el siguiente código:

#include <stdexcept>
#include <iostream>

struct ok {
    int _n;
    ok(int n) : _n(n) { std::cerr << "OK" << n << " born" << std::endl; }
    ~ok() {  std::cerr << "OK" << _n << " gone" << std::endl; }
};

struct problematic {
    ~problematic() noexcept(false) { throw std::logic_error("d-tor exception"); }
};

ok boo() {
    ok ok1{1};
    problematic p;
    ok ok2{2};
    return ok{3}; // Only constructor is called...
}

int main(int argc, char **argv) {
    try {boo();} catch(...) {}
}

Veo que el destructor de ok {3} no se llama, la salida es:

 OK1 born
 OK2 born
 OK3 born
 OK2 gone
 OK1 gone

¿Es el comportamiento esperado para C ++ 14?

Ediciones:

Compilando con gcc 6.3


Según el estándar, este comportamiento es incorrecto y esto ya se ha mencionado en la sección de comentarios de la pregunta. Esto se indica en la sección sobre el eel.is/c++draft/except.ctor#2 .

Según los informes de defectos en open-std.org , han sido conscientes de que las implementaciones (GCC y Clang) estaban equivocadas al respecto tan pronto como 2015-09-28. Pero la resolución propuesta fue solo en febrero de 2016 y los compiladores (GCC y Clang) aún no han incluido esta solución.

Resolución propuesta (febrero, 2016):

Cambie 18.2 [except.ctor] párrafo 2 como sigue:
El destructor se invoca para cada objeto automático del tipo de clase construido, pero aún no destruido, desde que se ingresó el bloque try. Si se lanza una excepción durante la destrucción de variables temporales o locales para una declaración de retorno (9.6.3 [stmt.return]), también se invoca el destructor para el objeto devuelto (si existe). Los objetos son destruidos en el orden inverso de la finalización de su construcción. [Ejemplo:

  struct A { };

  struct Y { ~Y() noexcept(false) { throw 0; } };

  A f() {
    try {
      A a;
      Y y;
      A b;
      return {};   // #1
    } catch (...) {
    }
    return {};     // #2
  }

En el # 1, el objeto devuelto de tipo A se construye. Luego, la variable local b se destruye (9.6 [stmt.jump]). A continuación, la variable local y se destruye, lo que provoca el desenrollamiento de la pila, lo que resulta en la destrucción del objeto devuelto, seguido de la destrucción de la variable local a. Finalmente, el objeto devuelto se construye de nuevo en el # 2. —En ejemplo]

Se han presentado errores contra este problema tanto en GCC como en Clang .

Los comentarios sobre el informe de error de GCC indican que es claramente un error.

Jonathan Wakely comenta:

Ahora es 2013, así que lo más sensato es no devolver el valor si tu destructor puede lanzar.

Y otro usuario:

Sí, me di cuenta, y Clang también ha tenido un error en su contra que ha languidecido durante años. Sin embargo, el comportamiento es incorrecto.





object-lifetime