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 

undef. behaviour in ctor-exc. handlers

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language (comp.lang.c++)
View previous topic :: View next topic  
Author Message
Klaus Ahrens
Guest





PostPosted: Tue Nov 29, 2005 12:20 pm    Post subject: undef. behaviour in ctor-exc. handlers Reply with quote



hi all,

acoording to the c++ standard

"15.3.
- -10- Referring to any non-static member or base class of an object in
the handler for a function-try-block of a constructor or destructor for
that object results in undefined behavior."

it is not allowed to refer to l (delete lWink in the following code

#include <iostream>
#include <memory>

using namespace std;

struct L {
L() { cout<<"L() at "< ~L() { cout<<"~L() at "< };

class X {
public:
L* l;
X() try : l(new L) {
cout<<"X() at "< }
catch (...) { delete l; throw; }

~X(){
cout<<"~X() at "< delete l;
}
};

int main(){
try {
X* p = new X;
delete p;
}
catch(...) { std::cout<<"some exception occured"< }

i wonder why this has been declared such, because it leads directly
to leaking local ressources. i know herb sutters arguments from 'more
exc. c++' (item 1Cool where a local pointer could refer to a meanwhile
destoyed subobject (as i understand it). but this seems to be a very
rare situation.

moreover compiled with g++ (3.3.5) the output is

L() at 0x804a018
X() at 0x804a008
~X() at 0x804a008
~L() at 0x804a018

without the leaking L

any idea ?

--
mfg
k ahrens
_____________________________________________
phone +49 30 2093 3113 Smile
fax +49 30 2093 3112 __________________
mailto:ahrens (AT) informatik (DOT) hu-berlin.de
http://www.informatik.hu-berlin.de/~ahrens
____________________________________________
Back to top
mlimber
Guest





PostPosted: Tue Nov 29, 2005 1:47 pm    Post subject: Re: undef. behaviour in ctor-exc. handlers Reply with quote



Klaus Ahrens wrote:
Quote:
hi all,

acoording to the c++ standard

"15.3.
- -10- Referring to any non-static member or base class of an object in
the handler for a function-try-block of a constructor or destructor for
that object results in undefined behavior."

it is not allowed to refer to l (delete lWink in the following code

#include #include
using namespace std;

struct L {
L() { cout<<"L() at "< ~L() { cout<<"~L() at "< };

class X {
public:
L* l;
X() try : l(new L) {
cout<<"X() at "< }
catch (...) { delete l; throw; }

This is not legal C++. If your compiler allows such syntax (as you
imply below), it is non-conformant.

Quote:

~X(){
cout<<"~X() at "< delete l;
}
};

int main(){
try {
X* p = new X;
delete p;
}
catch(...) { std::cout<<"some exception occured"< }

i wonder why this has been declared such, because it leads directly
to leaking local ressources. i know herb sutters arguments from 'more
exc. c++' (item 1Cool where a local pointer could refer to a meanwhile
destoyed subobject (as i understand it). but this seems to be a very
rare situation.

moreover compiled with g++ (3.3.5) the output is

L() at 0x804a018
X() at 0x804a008
~X() at 0x804a008
~L() at 0x804a018

without the leaking L

But your code doesn't throw an exception. Try adding a second member to
X and throwing an exception in the second member's constructor:

class MyException {};
class M { M() { throw MyException(); } };
class L {};
class X
{
L* l_;
M* m_;
public:
X()
try
: l_( new L ),
m_( new M )
{}
catch( const MyException& e )
{
// Automatic rethrow of e here
}
};

Now l_ is leaked.

Quote:

any idea ?

Perhaps this is the same material from Herb Sutter that you're
referring to, but he says ([url]http://www.gotw.ca/gotw/066.htm):[/url]

"[O]nce you get into your constructor try-block's handler, any local
variables in the constructor body are also already out of scope, and
you are guaranteed that no base subobjects or member objects exist any
more, period. You can't even refer to their names. Either the parts of
your object were never constructed, or those that were constructed have
already been destroyed. So you can't be cleaning up anything that
relies on referring to a base or member of the class (and anyway,
that's what the base and member destructors are for, right?)."

In practice, that means you should use a smart pointer such as
std::auto_ptr instead of a raw pointer for all class members to prevent
leaking local resources.

The same link discusses the rationale for why C++ does things that way,
and I'll just commend it for your reading pleasure rather than recap it
here.

Cheers! --M


Back to top
Klaus Ahrens
Guest





PostPosted: Tue Nov 29, 2005 2:11 pm    Post subject: Re: undef. behaviour in ctor-exc. handlers Reply with quote



mlimber schrieb:
Quote:
Klaus Ahrens wrote:

hi all,

acoording to the c++ standard

"15.3.
- -10- Referring to any non-static member or base class of an object in
the handler for a function-try-block of a constructor or destructor for
that object results in undefined behavior."

it is not allowed to refer to l (delete lWink in the following code

#include #include
using namespace std;

struct L {
L() { cout<<"L() at "< ~L() { cout<<"~L() at "< };

class X {
public:
L* l;
X() try : l(new L) {
cout<<"X() at "< }
catch (...) { delete l; throw; }


This is not legal C++. If your compiler allows such syntax (as you
imply below), it is non-conformant.


~X(){
cout<<"~X() at "< delete l;
}
};

int main(){
try {
X* p = new X;
delete p;
}
catch(...) { std::cout<<"some exception occured"< }

i wonder why this has been declared such, because it leads directly
to leaking local ressources. i know herb sutters arguments from 'more
exc. c++' (item 1Cool where a local pointer could refer to a meanwhile
destoyed subobject (as i understand it). but this seems to be a very
rare situation.

moreover compiled with g++ (3.3.5) the output is

L() at 0x804a018
X() at 0x804a008
~X() at 0x804a008
~L() at 0x804a018

without the leaking L


But your code doesn't throw an exception. Try adding a second member to
X and throwing an exception in the second member's constructor:

class MyException {};
class M { M() { throw MyException(); } };
class L {};
class X
{
L* l_;
M* m_;
public:
X()
try
: l_( new L ),
m_( new M )
{}
catch( const MyException& e )
{
// Automatic rethrow of e here
}
};

Now l_ is leaked.


any idea ?


Perhaps this is the same material from Herb Sutter that you're
referring to, but he says ([url]http://www.gotw.ca/gotw/066.htm):[/url]

"[O]nce you get into your constructor try-block's handler, any local
variables in the constructor body are also already out of scope, and
you are guaranteed that no base subobjects or member objects exist any
more, period. You can't even refer to their names. Either the parts of
your object were never constructed, or those that were constructed have
already been destroyed. So you can't be cleaning up anything that
relies on referring to a base or member of the class (and anyway,
that's what the base and member destructors are for, right?)."

In practice, that means you should use a smart pointer such as
std::auto_ptr instead of a raw pointer for all class members to prevent
leaking local resources.

The same link discusses the rationale for why C++ does things that way,
and I'll just commend it for your reading pleasure rather than recap it
here.

Cheers! --M

i agree with your arguments with multiple ressources, indeed i forgot to

throw, but even with an exception in my X-ctor g++ produces (obviously
wrong):

L() at 0x804b018
X() at 0x804b008
~L() at 0x804b018
some exception occured

in general c++ guarantees leak-free constructor failures by deleting
memory of half baked objects (arrays) implicitly. why couldn't this be
extended to single-ressource-owning classes at least (as in my class X)???


--
mfg
k ahrens
_____________________________________________
phone +49 30 2093 3113 Smile
fax +49 30 2093 3112 __________________
mailto:ahrens (AT) informatik (DOT) hu-berlin.de
http://www.informatik.hu-berlin.de/~ahrens
____________________________________________

Back to top
Alf P. Steinbach
Guest





PostPosted: Tue Nov 29, 2005 2:47 pm    Post subject: Re: undef. behaviour in ctor-exc. handlers Reply with quote

* Klaus Ahrens:
Quote:
hi all,

acoording to the c++ standard

"15.3.
- -10- Referring to any non-static member or base class of an object in
the handler for a function-try-block of a constructor or destructor for
that object results in undefined behavior."

it is not allowed to refer to l (delete lWink in the following code

#include #include
using namespace std;

struct L {
L() { cout<<"L() at "< ~L() { cout<<"~L() at "< };

class X {
public:
L* l;
X() try : l(new L) {
cout<<"X() at "< }
catch (...) { delete l; throw; }

~X(){
cout<<"~X() at "< delete l;
}
};

int main(){
try {
X* p = new X;
delete p;
}
catch(...) { std::cout<<"some exception occured"< }

i wonder why this has been declared such, because it leads directly
to leaking local ressources.

No, the C++ rules don't.

The above program is invalid.

If you'd care to present a valid program and explain _why_ you think it
would leak, we can set you right (or perhaps it would leak, it's not
difficult to arrange for a program to leak memory).


--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Back to top
mlimber
Guest





PostPosted: Tue Nov 29, 2005 3:06 pm    Post subject: Re: undef. behaviour in ctor-exc. handlers Reply with quote

Klaus Ahrens wrote:
Quote:
mlimber schrieb:
Klaus Ahrens wrote:

hi all,

acoording to the c++ standard

"15.3.
- -10- Referring to any non-static member or base class of an object in
the handler for a function-try-block of a constructor or destructor for
that object results in undefined behavior."

it is not allowed to refer to l (delete lWink in the following code

#include <iostream
#include
using namespace std;

struct L {
L() { cout<<"L() at "< ~L() { cout<<"~L() at "< };

class X {
public:
L* l;
X() try : l(new L) {
cout<<"X() at "< }
catch (...) { delete l; throw; }


This is not legal C++. If your compiler allows such syntax (as you
imply below), it is non-conformant.


~X(){
cout<<"~X() at "< delete l;
}
};

int main(){
try {
X* p = new X;
delete p;
}
catch(...) { std::cout<<"some exception occured"< }

i wonder why this has been declared such, because it leads directly
to leaking local ressources. i know herb sutters arguments from 'more
exc. c++' (item 1Cool where a local pointer could refer to a meanwhile
destoyed subobject (as i understand it). but this seems to be a very
rare situation.

moreover compiled with g++ (3.3.5) the output is

L() at 0x804a018
X() at 0x804a008
~X() at 0x804a008
~L() at 0x804a018

without the leaking L


But your code doesn't throw an exception. Try adding a second member to
X and throwing an exception in the second member's constructor:

class MyException {};
class M { M() { throw MyException(); } };
class L {};
class X
{
L* l_;
M* m_;
public:
X()
try
: l_( new L ),
m_( new M )
{}
catch( const MyException& e )
{
// Automatic rethrow of e here
}
};

Now l_ is leaked.


any idea ?


Perhaps this is the same material from Herb Sutter that you're
referring to, but he says ([url]http://www.gotw.ca/gotw/066.htm):[/url]

"[O]nce you get into your constructor try-block's handler, any local
variables in the constructor body are also already out of scope, and
you are guaranteed that no base subobjects or member objects exist any
more, period. You can't even refer to their names. Either the parts of
your object were never constructed, or those that were constructed have
already been destroyed. So you can't be cleaning up anything that
relies on referring to a base or member of the class (and anyway,
that's what the base and member destructors are for, right?)."

In practice, that means you should use a smart pointer such as
std::auto_ptr instead of a raw pointer for all class members to prevent
leaking local resources.

The same link discusses the rationale for why C++ does things that way,
and I'll just commend it for your reading pleasure rather than recap it
here.

Cheers! --M

i agree with your arguments with multiple ressources, indeed i forgot to
throw, but even with an exception in my X-ctor g++ produces (obviously
wrong):

L() at 0x804b018
X() at 0x804b008
~L() at 0x804b018
some exception occured

in general c++ guarantees leak-free constructor failures by deleting
memory of half baked objects (arrays) implicitly. why couldn't this be
extended to single-ressource-owning classes at least (as in my class X)???

All constructed members of a class *are* implicitly destroyed when the
constructor (or any function) throws an exception, and that inclues raw
pointers that happen to be members. However, the standard rules for
pointers is that if the pointer is non-null and it goes out of scope
without being deleted (or somehow passing ownership), the object it
pointed to is leaked. A simpler example:

void Foo()
{
L* rawPtr = new L;
std::auto_ptr throw MyException();
}

In this code, rawPtr is leaked but autoPtr is not. The two key benefits
of smart pointers are that they free the programmer from having to
manually delete each new-ed object and that they provide exception
safety. Their use is not only good practice in the example with M and L
above; it is essential for a non-leaking program.

Cheers! --M


Back to top
Klaus Ahrens
Guest





PostPosted: Tue Nov 29, 2005 4:01 pm    Post subject: Re: undef. behaviour in ctor-exc. handlers Reply with quote

Alf P. Steinbach schrieb:
Quote:
* Klaus Ahrens:

hi all,

acoording to the c++ standard

"15.3.
- -10- Referring to any non-static member or base class of an object in
the handler for a function-try-block of a constructor or destructor for
that object results in undefined behavior."

it is not allowed to refer to l (delete lWink in the following code

#include #include
using namespace std;

struct L {
L() { cout<<"L() at "< ~L() { cout<<"~L() at "< };

class X {
public:
L* l;
X() try : l(new L) {
cout<<"X() at "< }
catch (...) { delete l; throw; }

~X(){
cout<<"~X() at "< delete l;
}
};

int main(){
try {
X* p = new X;
delete p;
}
catch(...) { std::cout<<"some exception occured"< }

i wonder why this has been declared such, because it leads directly
to leaking local ressources.


No, the C++ rules don't.

The above program is invalid.

i know this for sure, and i know that auto_ptrs are much better, but my
question is concerned with the rationale behind that rule !

Quote:

If you'd care to present a valid program and explain _why_ you think it
would leak, we can set you right (or perhaps it would leak, it's not
difficult to arrange for a program to leak memory).



Back to top
Alf P. Steinbach
Guest





PostPosted: Tue Nov 29, 2005 5:03 pm    Post subject: Re: undef. behaviour in ctor-exc. handlers Reply with quote

* Klaus Ahrens:
Quote:

i know this for sure, and i know that auto_ptrs are much better, but my
question is concerned with the rationale behind that rule !

Presumably you mean the rule 15.3/10 that if you refer to a non-static
member variable in a constructor's function try-block catch clause,
you're invoking Undefined Behavior

The reason is very simple: when you enter the catch clause the member
has already been destroyed, it does not exist anymore, or alternatively
it wasn't fully constructed, and did not ever come into existence; see
15.3/11.

Essentially a constructor function try-block is only useful for
converting a non-standard exception originating in the constructor's
initialization list, to a standard exception. The purpose of C++
'catch' is _not_ to do cleanup. The purpose is to fulfill contracts,
such as a constract about only throwing standard exceptions.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language (comp.lang.c++) 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.