Question

So I was just reading about the RAII pattern for non garbage collected languages, and this section caught my eye:

This limitation is typically encountered whenever developing custom classes. Custom classes in C# and Java have to explicitly implement the dispose method in order to be dispose-compatible for the client code. The dispose method has to contain explicit closing of all child resources belonging to the class. This limitation does not exist in C++ with RAII, where the destructor of custom classes automatically destructs all child resources recursively without requiring any explicit code.

Why is it that C++ can correctly track these resources that are allocated in the RAII pattern, but we don't get this lovely Stack Unwinding with the C# using construct?

Was it helpful?

Solution

Suppose an object O is composed of two resource-owning objects R and S. What happens if O is destroyed?

In C++ with RAII, objects can own other objects such that one object's destruction is necessarily coupled to the other's. If O owns R and S -- by storing them by value, or by owning something which in turn owns R and S (unique_ptr, container that stores R and S by value), then destruction of O necessarily destroys R and S. As long as the destructors of R and S properly clean up after themselves, O doesn't need to do anything manually.

In contrast, C# objects do not have an owner that decides when its lifetime ends. Even if O would be destroyed deterministically (which it generally isn't), R and S might be reachable by another reference. What's more, the way O refers to R and S is the same way any other local variable, object field, array element, etc. refer to R and S. In other words, there's no way to indicate ownership, so the computer can't decide when the object is supposed to be destroyed and when it was only a non-owning/borrowed reference. Surely you would not expect this code to close the file?

File f = GetAFile();
return f; // end of method, the reference f disappears

But as far as the CLR is concerned, the reference from the local f here is exactly the same as the reference from O to R/S.

TL;DR Ownership.

OTHER TIPS

In C++, objects have definite lifetimes. Automatic variables' lifetimes end when they go out of scope, and dynamically-allocated objects' lifetimes end when they get deleted.

In C#, most objects are dynamically allocated, and there is no delete. Therefore, objects don't have a defined point in time when they are "deleted". The closest thing you have, then, is using.

The short answer: When was the last time you cleaned up your own memory allocations/resource allocations in a Java/C# destructor? In fact, when was the last time you remember writing a Java/C# destructor?

Since you are responsible for cleaning up after yourself in C++, you HAVE to do the cleanup. Thus, when you stop using a resource (if you have written good quality code), it will immediately be cleaned up.

In managed languages, the garbage collector is responsible for doing the cleanup. A resource your allocate could still be there long after you stopped using it (if the garbage collector is implemented poorly). This is a problem when the managed objects are creating unmanaged resources (e.g. database connections). Which is why the Dispose methods exist - to tell those unmanaged resources to go away. Since the destructor doesn't get called until the garbage collector cleans up the memory, doing the cleanup there would still leave the (finite) resource open for longer than it needed to be.

Because to implement this correctly in C#, you'd need to somehow mark which objects the class owns and which objects are shared. Perhaps a syntax similar to this one:

// NOT VALID CODE
public class Manager: IDisposable
{
     // Tell the runtime to call resource.Dispose when disposing Manager
     using private UnmanagedResource resource;
}

My guess is they decided to not go down that road because if you have to mark the objects you own, you have to write code about it. And if you have to write code about it, you can just write it in the Dispose method, calling Dispose for the objects you own :)

In C++, object ownership is usually very clear - if you hold the instance itself, you own it. In C# you never hold the instance itself, you always hold a reference, and a reference can be something you own or something you use - there is no way to tell which is true for a specific instance.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top