 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Raymond Haeb Guest
|
Posted: Sun May 20, 2007 1:48 am Post subject: throw im Konstruktor und new |
|
|
Hallo,
class a
{
a(){throw std::exception();}
};
void f()
{
try
{
a* pa = new a;
}catch(const std::exception& e)
{
}
}
a wirft also im Konstruktor eine Ausnahme, dadurch gilt das Objekt als
nicht existent und es darf der Destruktor nicht aufgerufen werden. Wer
gibt dann den Speicher frei? Oder erkennt new das?
Raymond |
|
| Back to top |
|
 |
Thomas Maeder Guest
|
Posted: Sun May 20, 2007 9:53 pm Post subject: Re: throw im Konstruktor und new |
|
|
Raymond Haeb <ray.haeb (AT) gmx (DOT) de> writes:
| Quote: | class a
{
a(){throw std::exception();}
};
void f()
{
try
{
a* pa = new a;
}catch(const std::exception& e)
{
}
}
a wirft also im Konstruktor eine Ausnahme, dadurch gilt das Objekt als
nicht existent und es darf der Destruktor nicht aufgerufen werden. Wer
gibt dann den Speicher frei? Oder erkennt new das?
|
Letzteres.
Die Evaluierung eines new-Ausdrucks ist eine komplexe
Geschichte. U.a. muss der zuvor erfolgreich allozierte Speicher wieder
freigegeben werden, wenn die Initialisierung des zu erzeugenden
Objekts eine Exception wirft. |
|
| Back to top |
|
 |
Andreas Huennebeck Guest
|
Posted: Mon May 21, 2007 1:16 pm Post subject: Re: throw im Konstruktor und new |
|
|
Thomas Maeder wrote:
| Quote: | Raymond Haeb <ray.haeb (AT) gmx (DOT) de> writes:
class a
{
a(){throw std::exception();}
};
void f()
{
try
{
a* pa = new a;
}catch(const std::exception& e)
{
}
}
a wirft also im Konstruktor eine Ausnahme, dadurch gilt das Objekt als
nicht existent und es darf der Destruktor nicht aufgerufen werden. Wer
gibt dann den Speicher frei? Oder erkennt new das?
Letzteres.
Die Evaluierung eines new-Ausdrucks ist eine komplexe
Geschichte. U.a. muss der zuvor erfolgreich allozierte Speicher wieder
freigegeben werden, wenn die Initialisierung des zu erzeugenden
Objekts eine Exception wirft.
|
Ack. Schwierig wird es eigentlich erst mit halbkonstruierten Objekten:
class a
{
int* x;
int* y;
a(int num) : x(new int[num]), y(new int[num]) {}
~a() { delete[] y; delete[] x; }
};
Wenn jetzt beim zweiten new für y eine Exception geworfen wird, gibt
es ein Speicherleck, weil der Destruktor nicht gerufen wird.
Tschau
Andreas
--
Andreas Hünnebeck | email: acmh (AT) gmx (DOT) de
----- privat ---- | www : http://www.huennebeck-online.de
Fax/Anrufbeantworter: 0721/151-284301
GPG-Key: http://www.huennebeck-online.de/public_keys/andreas.asc
PGP-Key: http://www.huennebeck-online.de/public_keys/pgp_andreas.asc |
|
| Back to top |
|
 |
Daniel Albuschat Guest
|
Posted: Mon May 21, 2007 5:57 pm Post subject: Re: throw im Konstruktor und new |
|
|
Andreas Huennebeck wrote:
| Quote: | Thomas Maeder wrote:
Raymond Haeb <ray.haeb (AT) gmx (DOT) de> writes:
[snip]
a wirft also im Konstruktor eine Ausnahme, dadurch gilt das Objekt als
nicht existent und es darf der Destruktor nicht aufgerufen werden. Wer
gibt dann den Speicher frei? Oder erkennt new das?
Letzteres.
Die Evaluierung eines new-Ausdrucks ist eine komplexe
Geschichte. U.a. muss der zuvor erfolgreich allozierte Speicher wieder
freigegeben werden, wenn die Initialisierung des zu erzeugenden
Objekts eine Exception wirft.
Ack. Schwierig wird es eigentlich erst mit halbkonstruierten Objekten:
class a
{
int* x;
int* y;
a(int num) : x(new int[num]), y(new int[num]) {}
~a() { delete[] y; delete[] x; }
};
Wenn jetzt beim zweiten new für y eine Exception geworfen wird, gibt
es ein Speicherleck, weil der Destruktor nicht gerufen wird.
|
In dem Fall muss sich der ctor selbst darum kümmern, keinen halb
konstruierten Müll zurück zu lassen.
Dafür gibt es die selten gesehene Syntax:
#include <iostream>
#include <stdexcept>
using namespace std;
struct printer {
int a;
printer(int a): a(a) {
cout << "printer::printer(" << a << ")\n";
if( a == 10 )
throw runtime_error("Error");
}
~printer()
{ cout << "printer::~printer(" << a << ")\n"; }
};
struct leak {
printer a, b;
leak(int x, int y) try: a(x), b(y) { } catch(exception &e) {
cerr << "leak::leak(): " << e.what() << endl;
}
};
int main() {
leak(20,10);
}
Bei meinem GCC gibt es folgendes aus:
printer::printer(20)
printer::printer(10)
printer::~printer(20)
leak::leak(): Error
Command terminated
Warum er abschmiert ist mir irgendwie ein Rätsel, weil ich die
Exception ja nicht weiter werfe, sondern behandle...
Aber man sieht wenigstens, dass der dtor von printer::printer(20)
aufgerufen wird.
MfG,
Daniel |
|
| Back to top |
|
 |
Thomas Mang Guest
|
Posted: Mon May 21, 2007 8:42 pm Post subject: Re: throw im Konstruktor und new |
|
|
Daniel Albuschat wrote:
| Quote: | Andreas Huennebeck wrote:
Thomas Maeder wrote:
Raymond Haeb <ray.haeb (AT) gmx (DOT) de> writes:
[snip]
a wirft also im Konstruktor eine Ausnahme, dadurch gilt das Objekt als
nicht existent und es darf der Destruktor nicht aufgerufen werden. Wer
gibt dann den Speicher frei? Oder erkennt new das?
Letzteres.
Die Evaluierung eines new-Ausdrucks ist eine komplexe
Geschichte. U.a. muss der zuvor erfolgreich allozierte Speicher wieder
freigegeben werden, wenn die Initialisierung des zu erzeugenden
Objekts eine Exception wirft.
Ack. Schwierig wird es eigentlich erst mit halbkonstruierten Objekten:
class a
{
int* x;
int* y;
a(int num) : x(new int[num]), y(new int[num]) {}
~a() { delete[] y; delete[] x; }
};
Wenn jetzt beim zweiten new für y eine Exception geworfen wird, gibt
es ein Speicherleck, weil der Destruktor nicht gerufen wird.
In dem Fall muss sich der ctor selbst darum kümmern, keinen halb
konstruierten Müll zurück zu lassen.
Dafür gibt es die selten gesehene Syntax:
#include <iostream
#include <stdexcept
using namespace std;
struct printer {
int a;
printer(int a): a(a) {
cout << "printer::printer(" << a << ")\n";
if( a == 10 )
throw runtime_error("Error");
}
~printer()
{ cout << "printer::~printer(" << a << ")\n"; }
};
struct leak {
printer a, b;
leak(int x, int y) try: a(x), b(y) { } catch(exception &e) {
cerr << "leak::leak(): " << e.what() << endl;
}
};
int main() {
leak(20,10);
}
Bei meinem GCC gibt es folgendes aus:
printer::printer(20)
printer::printer(10)
printer::~printer(20)
leak::leak(): Error
Command terminated
Warum er abschmiert ist mir irgendwie ein Rätsel, weil ich die
Exception ja nicht weiter werfe, sondern behandle...
|
Siehe 15.3/16, Konstruktoren und Destruktoren sind Ausnahmen im
Ausnahme-system, da sie die exception am ende des handlers automatisch
weiterwerfen.
Ist auch logisch, stelle dir vor main schaut so aus:
int main() {
leak l(20, 10);
std::cout << l.a.a;
}
In leak existieren weder a noch b (a wird destruiert, b hat nie wirklich
gelebt). Somit lebt auch leak nicht (und Zugriff auf die member ist
logischerweise verboten). Die automatische Weitergabe der exception
teilt genau das mit (und verhindert nebenbei jeglichen Zugriff auf das
sowieso nicht-existente l-Objekt). |
|
| Back to top |
|
 |
Bob Hairgrove Guest
|
Posted: Mon May 21, 2007 8:48 pm Post subject: Re: throw im Konstruktor und new |
|
|
On Mon, 21 May 2007 14:57:05 +0200, Daniel Albuschat
<daniel (AT) happy (DOT) viming.de> wrote:
| Quote: | Aber man sieht wenigstens, dass der dtor von printer::printer(20)
aufgerufen wird.
|
Von printer::printer(10) (leak::b im Beispiel) wird der dtor
allerdings nicht aufgerufen, da das Objekt nie vollständig
konstruiert wurde. In diesem Fall nützt das Auffangen der Exception
auch gar nichts, da jeder weitere Zugriff auf leak::b undefiniertes
Verhalten verursachen würde. Besser wäre es, die Exception einfach
weiter zu reichen. Somit würde man nicht in Versuchung kommen, nach
der Ausnahme das leak-Objekt überhaupt zu benutzen.
--
Bob Hairgrove
NoSpamPlease (AT) Home (DOT) com |
|
| Back to top |
|
 |
Bob Hairgrove Guest
|
Posted: Mon May 21, 2007 8:53 pm Post subject: Re: throw im Konstruktor und new |
|
|
On Mon, 21 May 2007 10:16:34 +0200, Andreas Huennebeck <acmh (AT) gmx (DOT) de>
wrote:
| Quote: | Schwierig wird es eigentlich erst mit halbkonstruierten Objekten:
class a
{
int* x;
int* y;
a(int num) : x(new int[num]), y(new int[num]) {}
~a() { delete[] y; delete[] x; }
};
Wenn jetzt beim zweiten new für y eine Exception geworfen wird, gibt
es ein Speicherleck, weil der Destruktor nicht gerufen wird.
|
Dafür würden "smart pointers" gute Dienste erweisen (s. Scott Meyers,
"More Effective C++", Item 10: "Prevent resource leaks in
constructors").
--
Bob Hairgrove
NoSpamPlease (AT) Home (DOT) com |
|
| Back to top |
|
 |
Thomas Maeder Guest
|
Posted: Mon May 21, 2007 9:38 pm Post subject: Re: throw im Konstruktor und new |
|
|
Andreas Huennebeck <acmh (AT) gmx (DOT) de> writes:
| Quote: | Die Evaluierung eines new-Ausdrucks ist eine komplexe
Geschichte. U.a. muss der zuvor erfolgreich allozierte Speicher wieder
freigegeben werden, wenn die Initialisierung des zu erzeugenden
Objekts eine Exception wirft.
Ack. Schwierig wird es eigentlich erst mit halbkonstruierten Objekten:
class a
{
int* x;
int* y;
a(int num) : x(new int[num]), y(new int[num]) {}
~a() { delete[] y; delete[] x; }
};
Wenn jetzt beim zweiten new für y eine Exception geworfen wird, gibt
es ein Speicherleck, weil der Destruktor nicht gerufen wird.
|
U.a. deshalb gibt's std::vector. |
|
| Back to top |
|
 |
Thomas Maeder Guest
|
Posted: Mon May 21, 2007 9:42 pm Post subject: Re: throw im Konstruktor und new |
|
|
Daniel Albuschat <daniel (AT) happy (DOT) viming.de> writes:
| Quote: | In dem Fall muss sich der ctor selbst darum kümmern, keinen halb
konstruierten Müll zurück zu lassen.
Dafür gibt es die selten gesehene Syntax:
#include <iostream
#include <stdexcept
using namespace std;
struct printer {
int a;
printer(int a): a(a) {
cout << "printer::printer(" << a << ")\n";
if( a == 10 )
throw runtime_error("Error");
}
~printer()
{ cout << "printer::~printer(" << a << ")\n"; }
};
struct leak {
printer a, b;
leak(int x, int y) try: a(x), b(y) { } catch(exception &e) {
cerr << "leak::leak(): " << e.what() << endl;
}
};
int main() {
leak(20,10);
}
Bei meinem GCC gibt es folgendes aus:
printer::printer(20)
printer::printer(10)
printer::~printer(20)
leak::leak(): Error
Command terminated
Warum er abschmiert ist mir irgendwie ein Rätsel, weil ich die
Exception ja nicht weiter werfe, sondern behandle...
|
Tust Du nicht.
Function try blocks in Konstrutoren und Destruktoren behandeln
Exceptions nicht endgültig. Entweder sie werfen selbst eine Exception,
oder aber die ursprüngliche Exception wird weitergeworfen, als ob der
function try block eine throw-Anweisung ohne Argument enthalten
würde. Siehe 15.3/16 im Standard von 1998. |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|