473,382 Members | 1,526 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,382 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 2159
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,...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
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

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.