Non-deterministic destruction via GC is good for managing memory, and little else. It's especially good for cyclic object graphs, which refcounting can't automatically handle. It is notably very poor at managing I/O resources like file handles -- that's where determinism is an absolute requirement.
Refcounting is a natural extension of object destructors (like in C++), and works naturally with RAII.
Ultimately, if you don't have both features available, things get awkward:
- In C#, you must manually inherit from IDisposable, and write a Dispose() function at every level of your object graph. This is something the compiler writes for you in C++! (in C++, every object's destructor automatically calls every member's destructor)
- In C++, you must manually break reference cycles, either with the performance-killing weak_ptr, or by manually iterating the object graph to break all cycles from a well-defined moment.