c++ - Singleton con un objeto que tira en el ctor-¿accediendo de nuevo?
exception memory-management (2)
Puedo usar C ++ 11 o C ++ 14 (o incluso C ++ 17). Supongamos que tengo un objeto singleton
class MyInstance {
public:
MyInstance() {
throw std::runtime_exception("something went wrong"); // Ctor might throw
}
};
MyInstance& getInstance() {
static MyInstance obj;
return obj;
}
Ahora, me aseguré de que cada llamada a
getInstance
esté envuelta en un
try {
auto& inst = getInstance();
} catch(std::runtime_error& e) {
// do something
}
Lo que me pregunto ahora es:
¿qué sucede si
después de fallar una inicialización en el constructor y arrojar, atrapar e informar al usuario en los registros ... el programa pasa
nuevamente
en una ruta de código de
try
y vuelve a llamar a
getInstance
?
Hice algunas conjeturas pero no tengo idea si tienen razón:
El objeto tiene almacenamiento estático, por lo que solo se intentará construir una vez que lo piense.
¿Devolver una referencia a un objeto no construido me dará una referencia colgante y un comportamiento indefinido?
¿
unique_ptr
un
unique_ptr
como variable estática en lugar de
obj
resolver este problema para que pueda acceder al puntero varias veces y también verificar si el objeto se construyó correctamente (
if (uptr == TRUE)
)?
[stmt.dcl]/4:
la inicialización dinámica de una variable de alcance de bloque con duración de almacenamiento estático o duración de almacenamiento de subprocesos se realiza la primera vez que el control pasa por su declaración; dicha variable se considera inicializada una vez completada su inicialización. Si la inicialización sale lanzando una excepción, la inicialización no está completa, por lo que se volverá a intentar la próxima vez que el control ingrese la declaración. [..]
No hay necesidad de "adivinar";
puede
poner un seguimiento
std::cout
dentro de
MyInstance::MyInstance()
y llamar a
getInstance()
dos veces
.
😊
Tampoco hay necesidad de punteros inteligentes;
el objeto existe o no, y no hay forma de proceder dentro de
getInstance()
después de la declaración sin el objeto existente, ¡porque arrojó una excepción!
Por cierto, es
std::runtime_error
, no
std::runtime_exception
.
Si el constructor lanza el objeto
no se
inicializa.
Por lo tanto, si el control vuelve a pasar por
getInstance
, la inicialización también se realizará nuevamente.
[stmt.dcl] (énfasis mío)
4 La inicialización dinámica de una variable de alcance de bloque con duración de almacenamiento estático o duración de almacenamiento de subprocesos se realiza la primera vez que el control pasa por su declaración; dicha variable se considera inicializada una vez completada su inicialización. Si la inicialización sale lanzando una excepción, la inicialización no está completa, por lo que se volverá a intentar la próxima vez que el control ingrese la declaración . Si el control ingresa la declaración concurrentemente mientras se inicializa la variable, la ejecución concurrente esperará la finalización de la inicialización. Si el control vuelve a ingresar la declaración de forma recursiva mientras se inicializa la variable, el comportamiento es indefinido.