473,725 Members | 1,947 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Destructor: not gauranteed to be called?

I'm programming in VS C++.NET 2005 using cli:/pure syntax. In my code I have
a class derived from Form that creates an instance of one of my custom
classes via gcnew and stores the pointer in a member. However, I set a
breakpoint at the destructor of this instance's class and it was never
called!!! I can see how it might not get called at a deterministic time. But
NEVER?

So, I guess I need to know the rules about destructors. I would have thought
any language derived from C++ would always guarantee the destructor of an
instance of a class be called at some time, especially if created via
[gc]new and stored as a pointer.

Yes, I think I can deterministical ly destruct it via 'delete' and setting to
nullptr. But the point still kinda freaks me that the destructor is no
longer gauranteed to EVER be called. I feel like I should be worried since
it is sometimes important to do other things besided freeing up memory in a
destructor. In my case I discovered it becuase I'm communicating through a
serial port which I change the baud rate from the current speed, but then
changed it back in the destructor - only to find out the destructor was
NEVER called! Hence, the port died, and MY program wouldn't work on
subsequent runs since it assumed the port had been returned to the same baud
(and hence couldn't communicate with it anymore).

So, again, why is the destructor no longer gauranteed to be called, and what
are these new rules? Or am I being ignorant, and C++ never made such
assurances. Inquiring minds want to know! : )

[==P==]
Jan 31 '06 #1
35 3319
Peter Oliphant wrote:
I'm programming in VS C++.NET 2005 using cli:/pure syntax. In my code
I have a class derived from Form that creates an instance of one of
my custom classes via gcnew and stores the pointer in a member.
However, I set a breakpoint at the destructor of this instance's
class and it was never called!!! I can see how it might not get
called at a deterministic time. But NEVER?

So, I guess I need to know the rules about destructors. I would have
thought any language derived from C++ would always guarantee the
destructor of an instance of a class be called at some time,
especially if created via [gc]new and stored as a pointer.
Why would you think that when C++ makes no similar guarantee for pure native
C++? The destructor for an object on the heap is called when and if you
call delete on a pointer to that object. The situation is no different for
C++/CLI with respect the to destructor (which is IDisposable::Di spose for
C++/CLI).

Yes, I think I can deterministical ly destruct it via 'delete' and
setting to nullptr. But the point still kinda freaks me that the
destructor is no longer gauranteed to EVER be called. I feel like I
should be worried since it is sometimes important to do other things
besided freeing up memory in a destructor. In my case I discovered it
becuase I'm communicating through a serial port which I change the
baud rate from the current speed, but then changed it back in the
destructor - only to find out the destructor was NEVER called! Hence,
the port died, and MY program wouldn't work on subsequent runs since
it assumed the port had been returned to the same baud (and hence
couldn't communicate with it anymore).
So, again, why is the destructor no longer gauranteed to be called,
and what are these new rules? Or am I being ignorant, and C++ never
made such assurances. Inquiring minds want to know! : )


They're not new rules - it's the nature of objects on the heap. For managed
object on the GC heap, the Finalizer MAY be called if you don't delete the
object, but the CLR doesn't guarantee that finalizers are ever called
either.

-cd
Jan 31 '06 #2
Hi Carl!
Why would you think that when C++ makes no similar guarantee for pure native
C++? The destructor for an object on the heap is called when and if you
call delete on a pointer to that object. The situation is no different for
C++/CLI with respect the to destructor (which is IDisposable::Di spose for
C++/CLI).


Just as addition:

See: Destructors and Finalizers in Visual C++
http://msdn2.microsoft.com/en-us/library/ms177197.aspx

Also be aware that the desctructor might be called, even if the
constructor has thrown an expection!!!
See also: http://blog.kalmbachnet.de/?postid=60
--
Greetings
Jochen

My blog about Win32 and .NET
http://blog.kalmbachnet.de/
Jan 31 '06 #3
/rant on

I'm sorry, but this is VERY new info to me, and I've been doing OOP for
about 15 years! Personally, I think it is against the whole concept of a
destructor. Why bother to ever create one if there is no gaurantee it will
be called? To me (IMHO), OOP should have this pact with the programmer. The
constructor is to set up the creation of an instance. The destructor is for
clean-up. Thus, the destructor should be gauranteed to be called SOMETIME,
at the very latest at application exit. Otherwise I feel the C++ laguage is
at fault for anything my destructor was meant to make sure wasn't left in a
bad state, since THAT's what I wrote the destructor for, and thought it was
responsible for making sure eventually happened.

Let me make this clear. I have always realized that when GC wasn't in play
that if I created something (then via 'new') I had to destruct it manually
to avoid memory leaks. That is, it was never gauranteed the destructor would
be called unless I invoked it via a delete call. But, with the introduction
of GC, anything created as a gc object shouldn't need to be destructed
manually, as the application is suppose to keep track of whether something
is being used anymore by anyone before GC destroys it. But I always assumed
it would destroy it the same way one would manually destroy it, by calling
it's destructor. Could someone explain to me why NOT calling the destructor
upon GC destroying the object would EVER be a GOOD thing?

What I see emerging is this. GC was created to help with the concept that
destruction of an object is tough to do when who 'owns' it is unclear, or
when it is unclear whether everyone's done with it. This caused memory leaks
in the case that 'nobody' took final responsibility (or couldn't based on
the info available). But the solution to this is now generating another
issue. Lack of reliable destruction! Destruction is now not gauranteed at
any time you don't specifically delete it. BUT WAIT! The whole point of GC
was to AVOID having to know when to do delete. So, if we are forced to do
delete to insure the destructor get run, then what did we gain from
introducing GC? That is, if we now still have to delete at the right time,
this implies we know the instance is free to be destroyed. Thus, we lose the
advantage we got. Or more precisely, we have add complication that
introduces more possible pitfalls, and we are STILL required to tell the
application when to destroy something if we want our destructors have any
reliable meaning!

Further, this is now causing aditional problems. I reported a bug that is
very nasty via the feedback center. The bug is this: Try creating two
classes, both ref. Now create 142 stack sematic variables of one class in
the other. Oh yeah, be sure the classes have destructors. Put ZERO code in
these classes. Guess what? It won't compile, and will return a 'program too
complex' error! It further explains it can't build the destructor. Now,
comment out the destructor in the class the 142 instances are based on. NOW
it compiles! So, they have introduced complexity to such a point with the
way it deals with destructors that it can't handle it past 142 members! I
don't see that as progress...

And, again possibly showing my ignorance, when did finalizers come into
play? Is this part of the C++ standard?

Basically, I think things have gotten so complicated in this destructor area
that we have just traded one set of problems for another. If I can't rely on
the code I write specifically for the purpose of tidying things up from ever
getting called, it aint my fault if stuff isn't returned back to normal once
my code is done running. Heaven forbid anyone put the 'return the system
back' code in the destructor of an application based on a single class...
; )

/rant off

Ok I feel much better now... lol

[==P==]

PS - here is link to bug I reported:

http://lab.msdn.microsoft.com/produc...0-44bd02f398c6

"Carl Daniel [VC++ MVP]" <cp************ *************** **@mvps.org.nos pam>
wrote in message news:ef******** ******@TK2MSFTN GP11.phx.gbl...
Peter Oliphant wrote:
I'm programming in VS C++.NET 2005 using cli:/pure syntax. In my code
I have a class derived from Form that creates an instance of one of
my custom classes via gcnew and stores the pointer in a member.
However, I set a breakpoint at the destructor of this instance's
class and it was never called!!! I can see how it might not get
called at a deterministic time. But NEVER?

So, I guess I need to know the rules about destructors. I would have
thought any language derived from C++ would always guarantee the
destructor of an instance of a class be called at some time,
especially if created via [gc]new and stored as a pointer.


Why would you think that when C++ makes no similar guarantee for pure
native C++? The destructor for an object on the heap is called when and
if you call delete on a pointer to that object. The situation is no
different for C++/CLI with respect the to destructor (which is
IDisposable::Di spose for C++/CLI).

Yes, I think I can deterministical ly destruct it via 'delete' and
setting to nullptr. But the point still kinda freaks me that the
destructor is no longer gauranteed to EVER be called. I feel like I
should be worried since it is sometimes important to do other things
besided freeing up memory in a destructor. In my case I discovered it
becuase I'm communicating through a serial port which I change the
baud rate from the current speed, but then changed it back in the
destructor - only to find out the destructor was NEVER called! Hence,
the port died, and MY program wouldn't work on subsequent runs since
it assumed the port had been returned to the same baud (and hence
couldn't communicate with it anymore).
So, again, why is the destructor no longer gauranteed to be called,
and what are these new rules? Or am I being ignorant, and C++ never
made such assurances. Inquiring minds want to know! : )


They're not new rules - it's the nature of objects on the heap. For
managed object on the GC heap, the Finalizer MAY be called if you don't
delete the object, but the CLR doesn't guarantee that finalizers are ever
called either.

-cd

Jan 31 '06 #4
Peter Oliphant wrote:
Personally, I think it is against the whole
concept of a destructor. I agree : the point is that there is NO destructors in .NET!!! There are
finalizers, which are a different beast.CLI "destructor s" have been mapped
to finalizers as best as MS could (generating code that implement
IDisposable, etc...), but this is by no way a native C++ destructor.

Let me make this clear. I have always realized that when GC wasn't in
play that if I created something (then via 'new') I had to destruct
it manually to avoid memory leaks. That is, it was never gauranteed
the destructor would be called unless I invoked it via a delete call.
But, with the introduction of GC, anything created as a gc object
shouldn't need to be destructed manually, as the application is
suppose to keep track of whether something is being used anymore by
anyone before GC destroys it. The GC is asynchronous, and your never sure it will execute a finalizer for
a given object.(not the destructor mind you, since it doesn't exist, the
finalizer!).
The other point is that, since you don't know in which order finalizers are
run, you can't reference any external object from within a finalizer, so
you're really very limited in what you can do within them.

The whole point of the IDisposable interface is to circumvent this
limitation of the GC, although it is still an inferior solution compared to
the native, synchronous C++ destructor, IMHO.
What I see emerging is this. GC was created to help with the concept
that destruction of an object is tough to do when who 'owns' it is
unclear, or when it is unclear whether everyone's done with it. This
caused memory leaks in the case that 'nobody' took final
responsibility (or couldn't based on the info available). But the
solution to this is now generating another issue. Lack of reliable
destruction! Agreed. There is NO destruction in .NET (nor in Java).
Destruction is now not gauranteed at any time you don't
specifically delete it. BUT WAIT! The whole point of GC was to AVOID
having to know when to do delete. So, if we are forced to do delete
to insure the destructor get run, then what did we gain from
introducing GC? No more memory leaks... The main reason for GC is to avoid raw memory leaks,
not to get a better model for logical destruction of objects.
That is, if we now still have to delete at the right
time, this implies we know the instance is free to be destroyed. More precisely, we have to *Dispose* the object at the right time...
Thus, we lose the advantage we got. Or more precisely, we have add
complication that introduces more possible pitfalls, and we are STILL
required to tell the application when to destroy something if we want
our destructors have any reliable meaning!
Yep. I do not believe anyway the computer will ever be able to *guess* what
the programmer wants, so there will ever be a manual indication of when an
action must be done (including destruction/finalization/release of
ressource).
And, again possibly showing my ignorance, when did finalizers come
into play? Is this part of the C++ standard? No, they are part of the .NET standard. They are a very central feature of
..NET, and you should document yourself to get a firm grasp on the subtle
differences between destructors and finalizers.

To make the story short, a finalizer is an optional member function that is
possibly called (if it exists!) by the GC some time before the GC reclaims
the object memory and after the last reference on the object has been
released. You've got no guarantee at all on the order on which finalizers
for different objects execute.
Basically, I think things have gotten so complicated in this
destructor area that we have just traded one set of problems for
another.

Possible. Another explanation is perhaps you didn't master the differences
between finalizers and destructors, and you expected something of the system
without taking care of checking in the documentation wether your
expectations were justified.

Arnaud
MVP - VC

PS : IMHO, the Java, C# and Managed C++ choice of using the C++ destructor
syntax (~ClassName) to express the finalizer is a bad mistake that led many
developpers into misconceptions of that kind.
Jan 31 '06 #5
It seems like the discussion has come to realize the difference between
finalizers and destructors. The first is non-deterministic and loosely
coupled, whereas the later is deterministic.

I do think there is a misunderstandin g of the differences between
destructors in managed code and destructors in native code. While there are
differences, the discussion here hasn't highlighted any of them.

Arnaud Debaene wrote:
I agree : the point is that there is NO destructors in .NET!!! There are
finalizers, which are a different beast.CLI "destructor s" have been
mapped to finalizers as best as MS could (generating code that implement
IDisposable, etc...), but this is by no way a native C++ destructor.
It's unfortunate that C# decided to use the tilda syntax for finalizers, and
even more unfortunate that the old Managed C++ syntax did the same thing.
However, the CLR makes no mention of destructors... so there's no real
mapping to do. Destructors are a language level implementation, not a
runtime issue.
The whole point of the IDisposable interface is to circumvent this
limitation of the GC, although it is still an inferior solution
compared to the native, synchronous C++ destructor, IMHO.
I'm curious how IDisposable presents an inferior solution. From my
perspective as a language designer, I see IDisposable as the implementation
detail for destructors in C++. Really, you don't have to know anything about
IDisposable to use destructors in C++/CLI. To me, the biggest limitation
imposed on destructors as a result of IDisposable is that all destructors
are public and virtual. I actually that's a good thing, and it's a mistake
that unmanaged C++ allows destructors to be anything else.
Agreed. There is NO destruction in .NET (nor in Java).
The premise of this statement is flawed. Destruction is a language level
service, because only the language can determine when it is appropriate to
deterministical ly cleanup objects. Why? Because the programmer needs to be
involved - otherwise you deal with the infamous halting problem. The CLR is
a collection of services that can be supplied to a running program. As long
as we're dealing with Turing Machines, the CLR will never be able to provide
deterministic cleanup as a service.

So, that means deterministic cleanup must be moved to the language level.
The best way to accomplish that and maintain a sense of cross-language
functionality was to create a common API. That was IDisposable. From there,
it's a matter of how the languages treat destruction semantics. C++/CLI does
everything that unmanaged C++ does, including automatic creation of
destructors when embedded types have destructors.
No more memory leaks... The main reason for GC is to avoid raw memory
leaks, not to get a better model for logical destruction of objects.


While GC is primarily about memory leaks, I would argue it serves to do much
more. C++ is inherently not type safe because it allows for things like use
of an object after delete. GC in the context of a language like C++ is the
only way to achieve type safety.

Also, if you are truly using Object Oriented Programming, objects will
represent resources like files, network connections, UI, etc. This means
that memory has a direct correlation to other resources, so GC has the
potential to cleanup a lot more than just memory.

Lastly, deterministic cleanup is really bad at cleaning up in certain
situations. A frequent example is shared resources that form a dependency
cycle. The impact of reference counting is well understood, and all of the
practices applied to unmanaged C++ frequently result in fragile programs. In
situations like these, garbage collection is the best solution. The problem
that usually results is programmers don't adapt to a different environment,
and instead try to contort deterministic practices to a non-deterministic
environment.

The short story... writing robust code still requires smart people thinking
solutions all the way through.

--
Brandon Bray, Visual C++ Compiler http://blogs.msdn.com/branbray/
Bugs? Suggestions? Feedback? http://msdn.microsoft.com/productfeedback/
Jan 31 '06 #6
Brandon Bray [MSFT] wrote:
It's unfortunate that C# decided to use the tilda syntax for finalizers,
and
even more unfortunate that the old Managed C++ syntax did the same thing. Well, that's one point on which we agree ;-)
The whole point of the IDisposable interface is to circumvent this
limitation of the GC, although it is still an inferior solution
compared to the native, synchronous C++ destructor, IMHO.


I'm curious how IDisposable presents an inferior solution. From my
perspective as a language designer, I see IDisposable as the
implementation detail for destructors in C++. Really, you don't have
to know anything about IDisposable to use destructors in C++/CLI. To
me, the biggest limitation imposed on destructors as a result of
IDisposable is that all destructors are public and virtual. I
actually that's a good thing, and it's a mistake that unmanaged C++
allows destructors to be anything else.


I was thinking more about C# "raw" implementation of IDisposable (where the
compiler doesn't generate the Dispose method; nor the call to Dipose in
client code), because in this model, it becomes the responsability of the
client of an object to free the internal ressources held by the object, by
calling explicitely Dispose, or through the "using" keyword.
For this point, C++/CLI stack semantic is a huge step in the good direction
WRT to Managed C++ / C#.
Agreed. There is NO destruction in .NET (nor in Java).
The premise of this statement is flawed. Destruction is a language
level service, because only the language can determine when it is
appropriate to deterministical ly cleanup objects. Why? Because the
programmer needs to be involved - otherwise you deal with the
infamous halting problem. The CLR is a collection of services that
can be supplied to a running program. As long as we're dealing with
Turing Machines, the CLR will never be able to provide deterministic
cleanup as a service.


I agree, but I think we must go a step latter : What is generally called
"destructio n" is in fact a 2 parts process :

1) Logical destruction, which correspond to the user code in the
destructor/finalizer function. To be most usefull, this operation should be
synchronous with the release of the last reference to the object (ie, a
stack object goes out of scope, a heap object is not referenced anymore or
is dekleted in native C++), because it allows to implment the RAII idiom and
therefore make it much easier to write exception-safe code.
<troll - well perhaps not THAT troll>I would argue that it's almost
impossible to write a non-trivial exception-safe code without the RAII idiom
</troll>.

2) Resource automatic freeing (mainly memory) , which can be done
automagically and asynchrounously by a GC.

Both native C++ and .NET collapse those 2 distinct operations into one
concept (the destructor or the run-by-the-GC-finalizer), whereas IMHO they
should be more clearly separated. Again, CLI stack semantic with automatic
implementation of IDiposable and automatic call to Dispose is the right
answer IMHO.
So, that means deterministic cleanup must be moved to the language
level. The best way to accomplish that and maintain a sense of
cross-language functionality was to create a common API. That was
IDisposable. From there, it's a matter of how the languages treat
destruction semantics. C++/CLI does everything that unmanaged C++
does, including automatic creation of destructors when embedded types
have destructors. Yes, is is the intent. I am not sure however that stack semantics can bu
used in all cases to implement the RAII idiom.Well, I suspect one could
declare small "ref struct". The real problem of course is that it is
unusable from C# or VB.NET.

Nonetheless, I see your point about the fact that a common API (IDiposable)
was the best bet to tackle the problem in a language neutral manner. Too bad
that other languages (C#, VB.NET) took the easy and wrong road of letting
the Dispose call responsibility in the client hands.
Anyway, as a C++ bare-to-the-metal-performance-fan (sarcarsm...), I still
regret that IDisposable must go through a virtual call overhead.
No more memory leaks... The main reason for GC is to avoid raw memory
leaks, not to get a better model for logical destruction of objects.


While GC is primarily about memory leaks, I would argue it serves to
do much more. C++ is inherently not type safe because it allows for
things like use of an object after delete. GC in the context of a
language like C++ is the only way to achieve type safety.

Well, I would not call "type safety" the danger of dereferencing a dangling
pointer, but I take your point (for me, "type safety" is about the danger of
an incorrect cast that may run unnoticed).
Also, if you are truly using Object Oriented Programming, objects will
represent resources like files, network connections, UI, etc. This
means that memory has a direct correlation to other resources, so GC
has the potential to cleanup a lot more than just memory. If you use the IDiposable pattern, yes. The finalizer is much more limited
in what you can do, since you can't reference another object from within a
finalizer. The problem is that most developper know about finalizers (which
they think about as destructors), but don't know about IDisposable, or are
unaware of the stack semantics.
Lastly, deterministic cleanup is really bad at cleaning up in certain
situations. A frequent example is shared resources that form a
dependency cycle. The impact of reference counting is well
understood, and all of the practices applied to unmanaged C++
frequently result in fragile programs. Agreed. Let's say the ideal solution to this problem still remains to be
invented ;-)
The problem that usually
results is programmers don't adapt to a different environment, and
instead try to contort deterministic practices to a non-deterministic
environment. Yes, but implementors don't make our life easier when they use the same
syntax for finalizers and destructors!
The short story... writing robust code still requires smart people
thinking solutions all the way through.

Amen...

Arnaud
MVP - VC
Jan 31 '06 #7

"Peter Oliphant" <po*******@Roun dTripInc.com> skrev i meddelandet
news:u9******** ******@TK2MSFTN GP10.phx.gbl...
/rant on
Let me make this clear. I have always realized that when GC wasn't
in play that if I created something (then via 'new') I had to
destruct it manually to avoid memory leaks. That is, it was never
gauranteed the destructor would be called unless I invoked it via a
delete call. But, with the introduction of GC, anything created as a
gc object shouldn't need to be destructed manually, as the
application is suppose to keep track of whether something is being
used anymore by anyone before GC destroys it. But I always assumed
it would destroy it the same way one would manually destroy it, by
calling it's destructor. Could someone explain to me why NOT calling
the destructor upon GC destroying the object would EVER be a GOOD
thing?


Yes! :-)

GC is *not*destroying the object, it is reclaiming the memory space.

The object really lives forever, but its memory space can be reclaimed
when the object cannot be reached anymore.
Bo Persson
Jan 31 '06 #8
>Possible. Another explanation is perhaps you didn't master the differences
between finalizers and destructors, and you expected something of the
system without taking care of checking in the documentation wether your
expectations were justified.
I agree, but there's a problem. You see, how do you know when a change has
been made, or what the new features are, or if something exists that solves
your problem in VS C++.NET? Please don't tell me this info is easily
obtained.

MSDN2. You mean ten's of thousands of pages of doco with an inferior search
engine and everything in alphabetical order? With MSDN2 you have to
basically know the answer to look it up (like a dictionary's weakness, you
have to know how it is spelled to look up how it is spelled). It therefore
becomes a guessing game. What do I suppose MS named this feature? And new
feature get losts in ten's of thousands of pages of doco (and the what is
new area is VERY skimpy).

Another problem is that there is no convention as to what is made into a
'method' and what is made into a 'property'. Often, changing a property is
like a method (i.e., to change visibility change the Visible property, there
is no SetVisible() and SetInvisible() functions, which would of course be
another logical way to do this), and many methods are the equivalent of
properties (they return a state but have no affect). Add the fact that the
stuff is not organized by functionality, and you end up with the situation
thet if you want to be sure you are doing the right thing, you must read
EVERYTHING. Also, MS often leaves old pages up with old info, so one can
even try to look things up and end with dis-information, especially since
the MSDN2 search engine will, without warning, vector you over to the old
MSDN side. And, IMHO, the MSDN2 doco is written by people so well versed in
the subject they seem to forget they actually need to explain it (they
explain it tautologically, ala 'an integer variable stores an integer'). Or
they explain it in a misleading way. For example, there is a page in MSD2
that says the following:

http://msdn.microsoft.com/library/de...m/impdf_37.asp

" A variable declared as enum is an int."

Now, if I said the variable X is an int, you would expect to be able to
store an int in it, yes? But an ENUM variable will return an error if you
try to store an int in it (e.g., enum_var = int(1) is an error). This needs
more explanation, but that is the ENTIRE explanation (look at the link).
Also, look at this page describing the new SerialPort class:

http://msdn2.microsoft.com/en-us/lib...erialport.aspx

Note the detailed description of the sample code for this class. It talks
about how it is a null modem application, and even says you need two systems
to see it in full swing. Only one problem. MS forgot to put the sample code
on the page! Now I've reported this here, reported this in the Feedback
area. Two month later, still no sample code. This would this take, what, 5
minutes, to correct?

And THIS is what I'M suppose to get my knowledge of the VS C++.NET from?
<shiver>

Let's take the point at hand. How was I suppose to find out about these new
rules regarding destructors and finalizers? Why shouldn't I assume that an
UPGRADE would maintain ALL previous functionality and possibly add onto it.
Changes, IMHO, violate the concept of UPGRADE. They should call VS C++.NET
someting like C+++ (3 +'s) to make sure we are clear we need to learn all
its details, since if you assume it will behave like standard C++ you might
find yourself chasing bugs that are actually features!

There is just TOO much info regarding VS C++.NET. This is why when you say:
No, they are part of the .NET standard. They are a very central feature of
.NET, and you should document yourself to get a firm grasp on the subtle
differences between destructors and finalizers.
The reason is not lack of desire or ability, is is lack of knowing such info
exists or that changes were made in the first place. One only 'discovers'
these when code stops working when you do what use to work and now doesn't.
Then the only recourse to sound like a complete buffoon and ask in forums
like this what to do, coming across like a total amateur (even though I have
over 35 years of programming experience).

The real annoyance though comes when you point out a bug in the language and
the response it that it can't be changed because it would 'violate the C++
standard'. How is that even close to a justification when VS C++.NET
violates the standard whenever it sees fit to in most areas. For example,
did you know that if you apply the ToString() method to a Char[] it returns
with the EXACT SAME STRING every time, and it's something like "Char[]". I
reported this, and they said this couldn't bechanged since it would violate
the standard and might break someone's existing code. HUH? Who in HELL
depends on this behavior?

Oh well, so it goes...

[==P==]

"Arnaud Debaene" <ad******@clu b-internet.fr> wrote in message
news:eq******** ******@TK2MSFTN GP09.phx.gbl... Peter Oliphant wrote:
Personally, I think it is against the whole
concept of a destructor.

I agree : the point is that there is NO destructors in .NET!!! There are
finalizers, which are a different beast.CLI "destructor s" have been mapped
to finalizers as best as MS could (generating code that implement
IDisposable, etc...), but this is by no way a native C++ destructor.

Let me make this clear. I have always realized that when GC wasn't in
play that if I created something (then via 'new') I had to destruct
it manually to avoid memory leaks. That is, it was never gauranteed
the destructor would be called unless I invoked it via a delete call.
But, with the introduction of GC, anything created as a gc object
shouldn't need to be destructed manually, as the application is
suppose to keep track of whether something is being used anymore by
anyone before GC destroys it.

The GC is asynchronous, and your never sure it will execute a finalizer
for a given object.(not the destructor mind you, since it doesn't exist,
the finalizer!).
The other point is that, since you don't know in which order finalizers
are run, you can't reference any external object from within a finalizer,
so you're really very limited in what you can do within them.

The whole point of the IDisposable interface is to circumvent this
limitation of the GC, although it is still an inferior solution compared
to the native, synchronous C++ destructor, IMHO.
What I see emerging is this. GC was created to help with the concept
that destruction of an object is tough to do when who 'owns' it is
unclear, or when it is unclear whether everyone's done with it. This
caused memory leaks in the case that 'nobody' took final
responsibility (or couldn't based on the info available). But the
solution to this is now generating another issue. Lack of reliable
destruction!

Agreed. There is NO destruction in .NET (nor in Java).
Destruction is now not gauranteed at any time you don't
specifically delete it. BUT WAIT! The whole point of GC was to AVOID
having to know when to do delete. So, if we are forced to do delete
to insure the destructor get run, then what did we gain from
introducing GC?

No more memory leaks... The main reason for GC is to avoid raw memory
leaks, not to get a better model for logical destruction of objects.
That is, if we now still have to delete at the right
time, this implies we know the instance is free to be destroyed.

More precisely, we have to *Dispose* the object at the right time...
Thus, we lose the advantage we got. Or more precisely, we have add
complication that introduces more possible pitfalls, and we are STILL
required to tell the application when to destroy something if we want
our destructors have any reliable meaning!


Yep. I do not believe anyway the computer will ever be able to *guess*
what the programmer wants, so there will ever be a manual indication of
when an action must be done (including destruction/finalization/release of
ressource).
And, again possibly showing my ignorance, when did finalizers come
into play? Is this part of the C++ standard?

No, they are part of the .NET standard. They are a very central feature of
.NET, and you should document yourself to get a firm grasp on the subtle
differences between destructors and finalizers.

To make the story short, a finalizer is an optional member function that
is possibly called (if it exists!) by the GC some time before the GC
reclaims the object memory and after the last reference on the object has
been released. You've got no guarantee at all on the order on which
finalizers for different objects execute.
Basically, I think things have gotten so complicated in this
destructor area that we have just traded one set of problems for
another.

Possible. Another explanation is perhaps you didn't master the differences
between finalizers and destructors, and you expected something of the
system without taking care of checking in the documentation wether your
expectations were justified.

Arnaud
MVP - VC

PS : IMHO, the Java, C# and Managed C++ choice of using the C++ destructor
syntax (~ClassName) to express the finalizer is a bad mistake that led
many developpers into misconceptions of that kind.

Jan 31 '06 #9
Peter Oliphant wrote:
Possible. Another explanation is perhaps you didn't master the
differences between finalizers and destructors, and you expected
something of the system without taking care of checking in the
documentation wether your expectations were justified.
I agree, but there's a problem. You see, how do you know when a
change has been made, or what the new features are, or if something
exists that solves your problem in VS C++.NET? Please don't tell me
this info is easily obtained.


I don't say so. I say that, just as you have learned native C++, you should
learn C++/CLI, most probably in a book or a course if you find MSDN to be
too "dictionnar ish" (I agree with that).
Another problem is that there is no convention as to what is made
into a 'method' and what is made into a 'property'. Often, changing a
property is like a method (i.e., to change visibility change the
Visible property, there is no SetVisible() and SetInvisible()
functions, which would of course be another logical way to do this),
and many methods are the equivalent of properties (they return a
state but have no affect). Well, for me, the difference between function and property is just syntaxic
sugar, they are really the same and I don't see this as a problem.
And, IMHO, the MSDN2 doco is
written by people so well versed in the subject they seem to forget
they actually need to explain it
MSDN is a reference, just as a dictionnary or an encyclopedia. It is not
meant to be a teaching tool (through, IMHO, it do quite a good job as a
teaching tool too, thanks to the many articles beside the mere
classes/functions/properties reference pages, but i agree it can be quite
difficult to find what you are looking for when you are not used to it).
Anyway, have you ever tried Linux man-pages or Oracle 800 pages PDF
reference books before complaining about MSDN ;-)

<snip samples> And THIS is what I'M suppose to get my knowledge of the VS C++.NET
from? <shiver>
Have you looked at MS Press books?

Anyway, MSDN2 was supposed to be a Beta version of the documentation for the
Beta version of Visual 2005 (that's the way I understood it at least).
Now that Visual 2005 is on the shelves, it doesn't seems that Visual 2005
specific stuff has been merged in the "main" MSDN site. I am not sure why
and if the MSDN2 is there to stay as the definitive doc (that would be a bad
idea IMHO to have 2 different "release" MSDN sites), or if we are in a
transitory state.
Let's take the point at hand. How was I suppose to find out about
these new rules regarding destructors and finalizers? They are no new : It was the same story in Managed C++, through the syntax
was different. The really new thing is the stack semantic.
Why shouldn't I
assume that an UPGRADE would maintain ALL previous functionality and
possibly add onto it.
Changes, IMHO, violate the concept of UPGRADE.
They should call VS C++.NET someting like C+++ (3 +'s) to make sure
we are clear we need to learn all its details, since if you assume it
will behave like standard C++ you might find yourself chasing bugs
that are actually features! Well, you know, they do call it C++/CLI for a purpose! Anyway, I agree that
MS nomenclature is (as most often) very confusing.

The reason is not lack of desire or ability, is is lack of knowing
such info exists or that changes were made in the first place. One
only 'discovers' these when code stops working when you do what use
to work and now doesn't. Your only error was to expect that C++/CLI will react exactly as native C++.
There I must say that the MS commercial woodoo about "It Just Work", "simply
compile your old code and see it work like it used to" and the like is
misleading.
The real annoyance though comes when you point out a bug in the
language and the response it that it can't be changed because it
would 'violate the C++ standard'. Huuu??? What are you speaking about here?
How is that even close to a
justification when VS C++.NET violates the standard whenever it sees
fit to in most areas. For example, did you know that if you apply the
ToString() method to a Char[] it returns with the EXACT SAME STRING
every time, and it's something like "Char[]". I reported this, and
they said this couldn't bechanged since it would violate the standard
and might break someone's existing code. HUH? Who in HELL depends on
this behavior?


I don't understand you here... ToString is not part of the C++ standard! It
is the .NET standard (ECMA 335) that define the ToString method, and it
seems consistent to me, as this specification says that :

<quote ECMA 335> "default : System.Object.T oString is equivalent to calling
System.Object.G etType to obtain the System.Type object for the current
instance and then returning the result of calling the System.Object.T oString
implementation for that type.
Note : The value returned includes the full name of the type.
</quote>

and, on the other hand, ToString is not redefined for System.Array.
Therefore, according to usual override rules, the return value is as
expected.

Note : My quotes from the ECMA 335 standard are from the XML file definining
the BCL and available at
http://www.ecma-international.org/pu...ma-335-xml.zip.
See partition 4 of
http://www.ecma-international.org/pu...T/Ecma-335.pdf
for a description of this XML file

Arnaud
MVP - VC
Feb 1 '06 #10

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

Similar topics

52
27017
by: Newsnet Customer | last post by:
Hi, Statement 1: "A dynamically created local object will call it's destructor method when it goes out of scope when a procedure returms" Agree. Statement 2: "A dynamically created object will call it's destructor when it is made a target of a delete".
9
8273
by: sahukar praveen | last post by:
Hello, This is the program that I am trying. The program executes but does not give me a desired output. ********************************************** #include <iostream.h> #include <iomanip.h> #include <string.h>
11
10520
by: Stub | last post by:
Please answer my questions below - thanks! 1. Why "Derived constructor" is called but "Derived destructor" not in Case 1 since object B is new'ed from Derived class? 2. Why "Derived destructor" is called in Case 2 since only ~base() becomes "virtual" and ~Derived() is still non-virtual? 3. Does Case 3 show that we don't need any virtual destructor to make ~Derived() called? 4. Is "virtual destructor" needed only for Case 2?
16
1861
by: Timothy Madden | last post by:
Hy I have destructors that do some functional work in the program flow. The problem is destructors should only be used for clean-up, because exceptions might rise at any time, and destructors will be called for clean-up only. So how can I tell, from within the destructor, if the call has been made as part of normal flow of control and the destructor can play its functional role, or if the call has been made as a result of an...
6
7963
by: Squeamz | last post by:
Hello, Say I create a class ("Child") that inherits from another class ("Parent"). Parent's destructor is not virtual. Is there a way I can prevent Parent's destructor from being called when a Child object goes out of scope? Specifically, I am dealing with a C library that provides a function that must be called to "destruct" a particular struct (this struct is dynamically allocated by another provided function). To avoid memory
11
5307
by: Ken Durden | last post by:
I am in search of a comprehensive methodology of using these two object cleanup approaches to get rid of a number of bugs, unpleasantries, and cleanup-ordering issues we currently have in our 4-month old C#/MC++ .NET project project. I'd like to thank in advance anyone who takes the time to read and/or respond to this message. At a couple points, it may seem like a rant against C# / .NET, but we are pretty firmly stuck with this approach...
4
3807
by: Joe | last post by:
I am looking for the quintessential blueprint for how a C++ like destructor should be implemented in C#. I see all kinds of articles in print and on the web, but I see lots of discrepencies. For example ... C# Essentials (O'Reilly) - "Finalizers are class-only methods". Not sure what "class-only method" means in this context, but ususally I would assume that to mean it is static and would only be called once for the life of the...
14
3206
by: gurry | last post by:
Suppose there's a class A. There's another class called B which looks like this: class B { private: A a; public : B() { a.~A() } }
5
5522
by: junw2000 | last post by:
I use the code below to study delete and destructor. #include <iostream> using namespace std; struct A { virtual ~A() { cout << "~A()" << endl; }; //LINE1 void operator delete(void* p) { cout << "A::operator delete" << endl;
0
8752
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 effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9257
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9174
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 Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8096
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, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6702
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6011
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4517
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
3221
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2634
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.