c++ - una - Captura de excepciones desde la lista de inicializadores de un constructor
tipos de excepciones en c# (5)
Lea en http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/ )
Editar: después de más excavaciones, estos se denominan "bloques de prueba de función".
Confieso que no sabía esto hasta que fui a buscar. ¡Aprendes algo cada día! No sé si esto es una acusación de lo poco que puedo usar C ++ en la actualidad, mi falta de conocimiento de C ++ o las características bizantinas que ensucian el lenguaje. Ah, bueno, todavía me gusta :)
Para garantizar que las personas no tengan que saltar a otro sitio, la sintaxis de un bloque de prueba de función para los constructores resulta ser:
C::C()
try : init1(), ..., initn()
{
// Constructor
}
catch(...)
{
// Handle exception
}
Aquí hay uno curioso. Tengo una clase A. Tiene un elemento de clase B, que quiero inicializar en el constructor de A usando una lista de inicializadores, así:
class A {
public:
A(const B& b): mB(b) { };
private:
B mB;
};
¿Hay alguna forma de detectar las excepciones que podría lanzar el constructor de copias de mB mientras se sigue utilizando el método de la lista de inicializadores? ¿O tendría que inicializar mB dentro de las llaves del constructor para poder probar / atrapar?
No es particularmente bonito:
A::A(const B& b) try : mB(b)
{
// constructor stuff
}
catch (/* exception type */)
{
// handle the exception
}
No veo cómo harías eso con la sintaxis de la lista de inicializadores, pero también soy un poco escéptico de que puedas hacer algo útil al capturar la excepción en tu constructor. Depende del diseño de las clases, obviamente, pero ¿en qué caso vas a fallar en crear "mB", y todavía tienes un útil objeto "A"?
También podría permitir que la excepción se filtre y manejarla donde se llame al constructor de A.
Sé que ha pasado un tiempo desde que comenzó esta discusión. Pero esa construcción try-and-catch mencionada por Adam es parte del estándar C ++ y es compatible con Microsoft VC ++ y GNU C ++. Aquí está el programa que funciona. Por cierto, la captura genera automáticamente otra excepción para señalar sobre la falla del constructor.
#include <iostream>
#include <exception>
#include <string>
using namespace std;
class my_exception: public exception
{
string message;
public:
my_exception(const char* message1)
{
message = message1;
}
virtual const char* what() const throw()
{
cout << message << endl;
return message.c_str();
}
virtual ~my_exception() throw() {};
};
class E
{
public:
E(const char* message) { throw my_exception(message);}
};
class A
{
E p;
public:
A()
try :p("E failure")
{
cout << "A constructor" << endl;
}
catch (const exception& ex)
{
cout << "Inside A. Constructor failure: " << ex.what() << endl;
}
};
int main()
{
try
{
A z;
}
catch (const exception& ex)
{
cout << "In main. Constructor failure: " << ex.what() << endl;
}
return 0;
}
Sin embargo, podría trabajar con inicialización diferida, es decir, mantener un unique_ptr en Reader in MyClass y crearlo con new. De esta manera, ni siquiera necesita la bandera has_reader, pero puede ver si su unique_ptr es inicial o no.
#include <iostream>
#include <memory>
using namespace std;
class MyOtherClass
{
public:
MyOtherClass()
{
throw std::runtime_error("not working");
}
};
class MyClass
{
public:
typedef std::unique_ptr<MyOtherClass> MyOtherClassPtr;
MyClass()
{
try
{
other = std::make_unique<MyOtherClass>();
}
catch(...)
{
cout << "initialization failed." << endl;
}
cout << "other is initialized: " << (other ? "yes" : "no");
}
private:
std::unique_ptr<MyOtherClass> other;
};
int main()
{
MyClass c;
return 0;
}
Por supuesto, también hay soluciones sin usar excepciones en absoluto, pero asumí que este es un requisito previo en su configuración.