¿Por qué no se elimina un objeto que tiene un destructor con un comportamiento indefinido de efecto secundario en C++ 11?
memory-leaks c++11 (4)
Esta respuesta cita C ++ 11 Norma 3.8:
si no hay una llamada explícita al destructor o si una expresión de eliminación (5.3.5) no se usa para liberar el almacenamiento, el destructor no se debe invocar implícitamente y cualquier programa que dependa de los efectos secundarios producidos por el destructor se ha definido comportamiento.
La parte sobre el que no se llama al destructor es clara. Ahora suponga que el destructor omitido tuvo un efecto secundario que debería haber afectado el comportamiento del programa.
¿Por qué el comportamiento del programa no está definido ahora? ¿Por qué no se omiten los efectos secundarios (ya que no se llama al destructor) y el programa se ejecuta normalmente sin efectos secundarios?
Creo que esto se pone en el estándar para permitir la recolección de basura. Y para señalar que C ++ se comporta de manera diferente que otros lenguajes, al no invocar destructores durante la recopilación.
Específicamente dice que el almacenamiento puede reutilizarse sin llamar a los destructores de los objetos en esa área de memoria. Si el programa depende de los destructores que se están ejecutando, no funcionará como se esperaba.
Si no depende de los destructores, todo está bien.
En este caso, tenemos una respuesta precisa. La línea específica fue introducida para resolver CWG 1116 , "Aliasing of union members".
La parte importante es la primera parte de ese párrafo (el énfasis es mío):
Un programa puede terminar la vida útil de cualquier objeto al reutilizar el almacenamiento que ocupa el objeto ...
Si simplemente reutiliza el almacenamiento de un objeto cuyo destructor no ha sido llamado, entonces obtendrá un comportamiento indefinido. Por ejemplo, el objeto podría haber iniciado un hilo, o registrado una devolución de llamada, o alguna otra acción donde un componente externo podría esperar que el objeto aún existiera.
Tu pregunta no tiene sentido.
¿Por qué no se omiten los efectos secundarios (ya que no se llama al destructor) y el programa se ejecuta normalmente sin efectos secundarios?
Se saltan, porque el destructor los habría disparado y no se ha invocado.
Mi lectura de:
y cualquier programa que dependa de los efectos secundarios producidos por el destructor tiene un comportamiento indefinido.
es simple, lo veo a la luz de RAII. Ejemplo:
#include "Object.hpp"
struct Manager: private boost::noncopyable {
union Raw {
char _[sizeof(Object)];
Object o;
};
static Raw raw;
Manager() { new (raw.o) Object(); }
~Manager() { raw.o.~Object(); }
};
Ahora, si asignó un Manager
, se olvida de destruirlo y asigna uno nuevo, estoy en apuros porque estoy sobreescribiendo el almacenamiento del primer Object
creado con un segundo aunque todavía esté "vivo". Este es un comportamiento indefinido.