Quote:
Originariamente inviato da fero86
in questo, molto migliore IMO:
Codice:
class A {
public:
A() {
if (inizializzazione di A fallisce) {
throw false;
}
}
~A() {
cleanup di A;
}
};
class B {
public:
B() {
if (inizializzazione di B fallisce) {
throw false;
}
}
~B() {
cleanup di B;
}
};
class C {
public:
C() {
if (inizializzazione di C fallisce) {
throw false;
}
}
~C() {
cleanup di C;
}
};
{
A a;
B b;
C c;
esegui operazione che usa a, b e c;
}
|
Mi dispiace deluderti ma se gli scoped object rappresentano (o dovrebbero esserlo) una pratica comune in C++, un costruttore che solleva eccezioni invece non lo è, e anzi è altamente sconsigliato.
Ovviamente non sono io a dirlo ma un certo Herb Sutter
http://www.gotw.ca/gotw/066.htm di cui consiglio: Exceptional C++ e More Exceptional C++.
Il primo risultato è che non verrà mai chiamato il distruttore in quanto l'oggetto ha vita solo alla fine del costruttore ma se questo solleva un'eccezione non termina correttamente.
Un costruttore che solleva eccezioni ti porta ad usare i function try block in altre classi. I function try block sono obbligati a risollevare un'eccezione quindi ciò comporta che rischi di non portare a termine la costruzione di un'intera collezione di oggetti, nell'esempio tutte le classi che abbiano come variabile d'istanza un oggetto di tipo A o B o C e così ricorsivamente.
Ovvero rischi di ritrovarti al catch nel main:
Codice:
class ThrowChild
{
public:
ThrowChild()
{
throw exception("faccio terminare il programma");
}
};
class NoThrowChild
{
public:
NoThrowChild() try :tc(){}catch(...){throw exception("Houston abbiamo un problema"); }
private:
ThrowChild tc;
};
class MainNoThrow
{
public:
MainNoThrow() {}
private:
NoThrowChild ntc;
};
int main(int argc, char *argv[])
{
try
{
MainNoThrow nt;
}
catch(const exception & ex)
{
cout << ex.what() << endl;
exit(-1);
}
catch(...)
{
exit(-1);
}
return 0;
}