C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

throw im Konstruktor und new

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German)
View previous topic :: View next topic  
Author Message
Raymond Haeb
Guest





PostPosted: Sun May 20, 2007 1:48 am    Post subject: throw im Konstruktor und new Reply with quote



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





PostPosted: Sun May 20, 2007 9:53 pm    Post subject: Re: throw im Konstruktor und new Reply with quote



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





PostPosted: Mon May 21, 2007 1:16 pm    Post subject: Re: throw im Konstruktor und new Reply with quote



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





PostPosted: Mon May 21, 2007 5:57 pm    Post subject: Re: throw im Konstruktor und new Reply with quote

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





PostPosted: Mon May 21, 2007 8:42 pm    Post subject: Re: throw im Konstruktor und new Reply with quote

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





PostPosted: Mon May 21, 2007 8:48 pm    Post subject: Re: throw im Konstruktor und new Reply with quote

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





PostPosted: Mon May 21, 2007 8:53 pm    Post subject: Re: throw im Konstruktor und new Reply with quote

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





PostPosted: Mon May 21, 2007 9:38 pm    Post subject: Re: throw im Konstruktor und new Reply with quote

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





PostPosted: Mon May 21, 2007 9:42 pm    Post subject: Re: throw im Konstruktor und new Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German) All times are GMT
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.