473,418 Members | 1,977 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,418 software developers and data experts.

Unexpected behavior on exception

In C# (and C++/cli) the destructor will be called even if an exception
is thrown in the constructor. IMHO, this is unexpected behavior that can
lead to an invalid system state. So beware!

http://www.geocities.com/jeff_louie/oop30.htm

Regards,
Jeff

*** Sent via Developersdex http://www.developersdex.com ***
Jan 2 '06 #1
9 2165
Jeff Louie <je********@yahoo.com> wrote:
In C# (and C++/cli) the destructor will be called even if an exception
is thrown in the constructor. IMHO, this is unexpected behavior that can
lead to an invalid system state. So beware!

http://www.geocities.com/jeff_louie/oop30.htm


Why does the page say it's "non-standard" behaviour? I suspect by that
you mean "not as unmanaged C++ works" which isn't the same thing at
all. It's standard behaviour in terms of it being the behaviour the CLI
standard would suggest. (The object has been created, after all.)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jan 2 '06 #2
Hi Jon... I reworded the statement. But it is not only C++ that enforces
this idiom. Even the lowly PHP enforces this idiom. Knowing that the
destructor will only be called on a fully constructed object is integral
to the RAII idiom. IMHO it makes sense that if the _user_ defined
constructor code does not execute to completion then the _user_ defined
destructor code should not execute. This does not stop fully constructed
base objects from calling _their_ destructors. so if [[DefaultObject
alloc]init] succeeds but myObject = [[[DefaultObject alloc]init]myInit]
fails, go ahead and call the destructor of DefaultObject, but _don't_
call the destructor of myObject.

Regards,
Jeff

*** Sent via Developersdex http://www.developersdex.com ***
Jan 3 '06 #3
Jeff Louie wrote:
Hi Jon... I reworded the statement. But it is not only C++ that enforces
this idiom. Even the lowly PHP enforces this idiom. Knowing that the
destructor will only be called on a fully constructed object is integral
to the RAII idiom.
I don't see that it's that integral - it's easy enough to guard against
trying to release resources twice.
IMHO it makes sense that if the _user_ defined
constructor code does not execute to completion then the _user_ defined
destructor code should not execute. This does not stop fully constructed
base objects from calling _their_ destructors. so if [[DefaultObject
alloc]init] succeeds but myObject = [[[DefaultObject alloc]init]myInit]
fails, go ahead and call the destructor of DefaultObject, but _don't_
call the destructor of myObject.


Hmm. "Partially-constructed" objects still need to be garbage
collected, however - so why would they not need to be finalized? What
if the base class constructor succeeds, but the derived class
constructor then fails - would you expect the base class finalizer to
be called, but not the derived class finalizer?

The current behaviour seems consistent to me - you don't need any
special rules about when an object is deemed to be "finalizable". A
"partially-constructed" object is still an object - and may indeed be
used elsewhere, if a constructor (say) adds "this" to a list of
objects, or keeps a static reference somewhere. (Yes, those are both a
bad idea - just listing possibilities :)

In both cases you have to be careful - in the C++ semantics you need to
make absolutely sure that you release any resources acquired during
construction if an exception is thrown. In the CLR semantics you need
to make sure that you don't try to release something that was never
acquired (or which has already been released). I see the latter as
easier though, as there's a single finalizer but there may be many
constructors. Better to only have to be careful in one place :)

Jon

Jan 3 '06 #4

"Jeff Louie" <je********@yahoo.com> wrote in message
news:%2****************@TK2MSFTNGP11.phx.gbl...
Hi Jon... I reworded the statement. But it is not only C++ that enforces
this idiom. Even the lowly PHP enforces this idiom. Knowing that the
destructor will only be called on a fully constructed object is integral
to the RAII idiom. IMHO it makes sense that if the _user_ defined
constructor code does not execute to completion then the _user_ defined
destructor code should not execute. This does not stop fully constructed
base objects from calling _their_ destructors. so if [[DefaultObject
alloc]init] succeeds but myObject = [[[DefaultObject alloc]init]myInit]
fails, go ahead and call the destructor of DefaultObject, but _don't_
call the destructor of myObject.

Regards,
Jeff

*** Sent via Developersdex http://www.developersdex.com ***


If an exception propagates out of a constructor, you'll have to make sure
that your destructor (Finalize) can handle "partially contructed" objects.
Another option is to catch exceptions in the contructor and suppress
finalization, like:

class Foo {
public Foo()
{
try {
FunctionThatCanThrow();
}
catch(Exception) {
GC.SuppressFinalize(this);
throw;
}
resourceHandle = ....// allocate unmanaged resource that needs
clean-up.
}
~Foo()
{
if(resourceHandle)
... // clean-up
}

Willy.

Jan 3 '06 #5
In addition to the comments and options Jon and Willy offered, you can also
separate the construction of the object from the acquisition of resources
into two separate phases so that the constructor never throws an exception.
In the constructor set fields to known values (null, etc) to estiablish its
invariants, then use an Initialization method to acquire the resources.

FYI: If an exception is thrown from a static constructor then that type is
thereafter unusable in that appdomain - you will not be able to create
instances of that type in that AppDomain.

"Jeff Louie" <je********@yahoo.com> wrote in message
news:%2****************@TK2MSFTNGP11.phx.gbl...
Hi Jon... I reworded the statement. But it is not only C++ that enforces
this idiom. Even the lowly PHP enforces this idiom. Knowing that the
destructor will only be called on a fully constructed object is integral
to the RAII idiom. IMHO it makes sense that if the _user_ defined
constructor code does not execute to completion then the _user_ defined
destructor code should not execute. This does not stop fully constructed
base objects from calling _their_ destructors. so if [[DefaultObject
alloc]init] succeeds but myObject = [[[DefaultObject alloc]init]myInit]
fails, go ahead and call the destructor of DefaultObject, but _don't_
call the destructor of myObject.

Regards,
Jeff

*** Sent via Developersdex http://www.developersdex.com ***

Jan 4 '06 #6
Willy and MSFT... I added your suggestions to the article.

Thanks,
Jeff

*** Sent via Developersdex http://www.developersdex.com ***
Jan 8 '06 #7
On Sun, 01 Jan 2006 19:32:15 -0800, Jeff Louie <je********@yahoo.com>
wrote:
In C# (and C++/cli) the destructor will be called even if an exception
is thrown in the constructor. IMHO, this is unexpected behavior that can
lead to an invalid system state. So beware!


Unexpected to you perhaps. I can't see anything else happening as
preferable. If an object gets half way through construction and
fails for /any/ reason, I would certainly want the destructor called
to clean up any partially constructed stuff and release any partially
aquired resources.

Oz
--
A: Because it fouls the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jan 8 '06 #8
Hello ozbear,
Unexpected to you perhaps. I can't see anything else happening as
preferable. If an object gets half way through construction and fails
for /any/ reason, I would certainly want the destructor called to
clean up any partially constructed stuff and release any partially
aquired resources.


I agree. It can be quite awkward at first but taken the other way you would
have to implement a destructor twice. Once in the destructor and once in
the constructor to handle any un-expected errors.

--
Jared Parsons
ja****@beanseed.org
http://jaredparsons.blogspot.com
Jan 8 '06 #9
Ozbear... It's not that simple. First, say a reference counter is
incremented in
the constructor. In standard C++ I know that the destructor will only be
called if the constructor completes successfully so that I know that I
can
decrement the reference count in the destructor. Period. In C# there is
no
such guarantee. I need to code around this. If I don't, I could
decrement the
reference counter in the destructor and another object can try to call a
method on a prematurely released resource.

Secondly, there is _no_ guarantee that the destructor will be called in
a timely
manner! If an exception is thrown in the constructor in a using
construct,
Dispose is _not_ called. The resource will only be released when the
garbage
collector gets around to it.

So IMHO, cleaning up the resources in the constructor on exception and
then
call GC.SuppressFinalize(this) is the preferable solution for
deterministic
release of unmanaged resources.

Regards,
Jeff
Unexpected to you perhaps. I can't see anything else happening as

preferable. If an object gets half way through construction and
fails for /any/ reason, I would certainly want the destructor called
to clean up any partially constructed stuff and release any partially
aquired resources.<

*** Sent via Developersdex http://www.developersdex.com ***
Jan 9 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Robert Mazur | last post by:
MySQL 5.0 alpha (binary install) on Solaris 9 -or- RedHat 8.0 mysql-connector-java-3.0.8-stable ----------------------- Is there something different going on with JDBC and the alpha version...
2
by: Attila Feher | last post by:
Hi all, I have not done much work around exceptions; and even when I do I avoid exception specifications. But now I have to teach people about these language facilities, so I am trying them out...
3
by: Teddy | last post by:
Hello all According to "Think in C++ Volume2", the code below should run smoothly: #include <iostream> #include <exception> using namespace std; class ex { };
6
by: Samuel M. Smith | last post by:
I have been playing around with a subclass of dict wrt a recipe for setting dict items using attribute syntax. The dict class has some read only attributes that generate an exception if I try to...
3
by: Rahul Anand | last post by:
As per our requirements we have a web service which internally connects (Simple HTTP Post Request) to a remote server to initiate some work. We are calling the web service method asynchronously...
2
by: bb | last post by:
Hi, I am using gcc v4.0.2 on fedora core 4 (2.6.16). Any reason why the handler set thru' set_unexpected() never gets called in the following code? --------- Code ------------- #include...
0
by: Mahesh Devjibhai Dhola | last post by:
Hi, I am getting the following exception when using webservice.. "The underlying connection was closed: An unexpected error occurred on a receive" I am not getting any innerexception so no clue...
3
by: Anup Daware | last post by:
Hi Group, I am facing a strange problem here: I am trying to read xml response from a servlet using XmlTextWriter. I am able to read the read half of the xml and suddenly an exception:...
2
by: mbeachy | last post by:
Some rather unexpected behavior in the set_default/set_defaults methods for OptionParser that I noticed recently: <Option at 0x-483b3414: -r/--restart> {'restart': None} {'retart': False,...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.