views:

204

answers:

4

As far as I know, in case of an uncaught exception, C++ destroys the local variables immediately, Java releases the references and leaves the rest for the garbage collector.

Is this right? What exactly is the difference between Java and C++ on this issue? in other words, which of these two languages is considered better in terms of stack unwinding issue? :)

+4  A: 

Stack unwinding is specifically calling destructors of all fully constructed objects up the call chain up to the point where the exception is caught.

Java simply has no stack unwinding - it doesn't do anything to objects if an exception is thrown. You have to handle the objects yourself in catch and finally blocks. This is mainly why C# introduced using statements - they simplify calling IDisposable.Dispose(), but again that's not the complete replacement for C++ stack unwinding.

sharptooth
To ask the question here may be better:why doesn't Java have a destructor like mechanism that is called when the garbage collector collects the object? That way, we would guarantee our resources to be closed; no matter when, since we are interested more in handling the memory leaks.
sahs
+2  A: 

You are quite correct, C++ destroys all local variables, in reverse order, as it exits each function on the stack - just as if you were programmatically executing return - and out of main().

quamrana
+5  A: 

I'm going to get flamed for this but...

C++ is hands down better than Java on the stack unwinding front--there's just no contest. C++ object destructors fire all the way back up the stack until the catch point is reached--releasing all managed resources gracefully along the way.

As you said, Java leaves all of this at the mercy of the non-deterministic garbage collector (worst case) or in the hands of whatever explicitly crafted finally blocks you've littered your code with (since Java doesn't support true RAII). That is, all the resource management code is in the hands of the clients of each class, rather than in the hands of the class designer where it should be.

That said, in C++, the stack unwinding mechanism only functions properly if you're careful to ensure that destructors themselves do not emit exceptions. Once you've got two active exceptions, your program abort()'s without passing go (and of course without firing any of the remaining destructors).

Drew Hall
In C++ the objects created on the stack are get the destructor called, but that not happens for the objects on the heap, referenced by a pointer with in a local variable.
Mnementh
@Mnementh: except for heap objects that are properly owned by an object with a destructor.
quamrana
@quamrana: Yes, as I explained in my answer.
Mnementh
This behaviour has absolutely nothing to do with stack unwinding, and everything with the possibility of allocating objects on the stack in the first place. I'll take non-deterministic garbage collection over manual memory management every day. Java beats C++ on memory management hands down - there's just no contest.
Michael Borgwardt
Drew Hall
Java stack unwinding is broken, as explained it works like in C++. But Java has no explicit object creation on the stack. You're right that management of resources besides memory is somewhat harder in Java, but for the case of an exception the OP is talking about, you have to take care in C++, to avoid memory leaks for heap-objects. That's also hard. So as always: For some cases C++ works better, for other Java. No flaming from either side is needed.
Mnementh
@Mnementh: In C++ you just have to have discipline: heap allocations are held by smart pointers, period. End of memory management problems. Sorry, I didn't mean to rant about Java but sometimes I feel like they created "a better C++" by removing all the good parts of C++.
Drew Hall
@Michael Borgwardt: Unless you're, like me, writing a commercial Java application... I start to regret Java a lot: non-deterministic GC is a major pain when you're shipping to hundreds and soon thousands of users. Good luck explaining to them why suddenly their app seems stuck: oh but this is normal you know, this *rocks*, this is Java's non-deterministic GC! This is much better than C++! Look, as a programmer, I don't care about freeing objects! As a user you do of course. Btw if there's one thing that I hate about IntelliJ it's when it's doing a full GC... Maybe Java ain't perfect?
Webinator
@WizardOfOdds: your users care about freeing objects? Nonsense. They care about apps not crashing, which is decidedly easier to do in Java, and about performance, which may be a bit harder, but is certainly not impossible. Problem with GC pauses usually can be addressed by tuning the GC options of the JVM.
Michael Borgwardt
@Drew Hall: Self-limiting to smart-pointers? Why do you cut out the good parts of C++? ;-)
Mnementh
About this RAII thing, if we have a problem with resources (say, a db connection) in Java, why doesn't it have a destructor like mechanism that is called when the garbage collector collects the object.That way, we would guarantee that the resource would be closed, no matter when. Right?
sahs
@Michael Borgwardt: You are contradicting yourself: On one hand, you tell Drew Hall **Java beats C++ on memory management hands down**, and when contradicted, tell WizardOfOdds **your users care about freeing objects?**. C++ RAII mechanism is unmatched when compared with Java's broken resource handling. At least, the C# people got it right with their `using` keyword and their **dispose** pattern.
paercebal
@paercebal where do you see a contradiction? The statement that *users* care about freeing objects is patently absurd; they don't have the fainted idea what "freeing objects" even means. And while Java's handling of non-memory resources might not be as good as RAII (in cases where RAII can be applied), this is a small price to pay for not having to deal with manual memory management.
Michael Borgwardt
@sahs: um... that mechanism exists. It's called "finalizer". The problem with it is that since it depends on the garbage collection of the related object, it can be delayed arbitrarily.
Michael Borgwardt
+1  A: 

For the stack do both the same: They release the stack for the blocks that you leave with the exception. In Java all primitive types (int, double etc.) are saved directly, local variables of this type are released in this moment. All objects are saved through references in local variables, so the references are removed, but the objects itself stay on the heap. If this was the last reference to the object, they are released on the next garbage collection. If in C++ are objects created on the heap and the local variables keep a pointer, the objects on the heap aren't released automatically, they stay on the heap forever (yes, you get a MEMORY LEAK). If you have saved objects on the stack, then the destructor is called (and may release other referenced objects on the heap).

Mnementh
True, but smart pointers in C++ let you destroy heap-allocated objects automatically as well.
sharptooth
Right, smart-pointers work different.
Mnementh
In fact they work exactly the same way. Stack unwinding calls their destructors and their destructors in turn destroy the corresponding heap-allocated objects.
sharptooth
Yes, that's the way they are implemented. I meant they work different, as you don't need that much care to avoid memory-leaks by using smart pointers.
Mnementh
@Mnementh : What sharptooth wanted to tell, I guess, is that you should have mentionned smart pointers in your discussion, too. Something like: *The objects are still on the heap, but a stack-based smart pointer will free it as soon as possible*.
paercebal