Originally Posted by
anon
I have sniffed some C# and while destructor calls don't seem to be guaranteed, they have something called a using statement, so if the file object is IDisposable you'd put the file operations in a using block. (It would still be possible to have live references to disposed IDisposables? And it would be possible to forget to use the using block. Which makes me like C++'s destructors.)
To elaborate, the using() statement is an exception-safe manual call to close, that looks like this:
Code:
using (var v = new SomeClass())
{
// code
}
and is basically:
Code:
var v = new SomeClass();
try
{
// code
}
finally
{
v.Dispose();
}
In my opinion, it is a sad mixing of language and standard library -- the object in the using() must implement the IDisposable interface, so as .Dispose() can be called. Worse, if you have a simple function that just has three objects in it, you're suddly three scopes and tabs deep - generally for a total of 5 * 4 = 20 spaces. (+2 tabs for class & function).
Furthermore, you have to do this on so many objects, I often wonder if the garbage collection acutally helps. Whereas you might have:
Code:
using(Lock a = first_mutex.Lock())
{
using(Lock b = second_mutex.Lock())
{
using(Lock c = third_mutex.Lock())
{
// do something.
}
}
}
...which in C++ is:
Code:
Lock a = first_mutex.lock();
Lock b = second_mutex.lock();
Lock c = third_mutex.lock();
// do something.
Which is easier to read, write, and maintain? (And, the C++ will likely free up more resources faster, as the C# one still leaves memory allocated until the GC gets it.)
In short: Don't underestimate the power of RAII. It's an immensely powerful C++ idiom, and when used correctly, it can make quite elegant code. Don't write C code in C++. Write C++, and let RAII take care of you.