>> Refcounting works just as well in C# as it does in C++, you just have to implement the refcounting logic in your Dispose method, similar to how shared_ptr implements its refcounting logic in the destructor. And actually, alankila already pointed this out, so I don't even know why I bother repeating it...
Yes alankina already pointed it out, and it is wrong. Refcounting simply does not work in C#. Because all the helper classes, collections e.t.c, do NOT implement IDispose. That's the point. You cannot implement refcounting when half the standard library is working against you.
>> You would, because if you end up holding a reference to an object with refcount 0, that means you forgot to increase the reference count at some point, and that is perfectly possible with a shared_ptr<T>. You could call .get() on the shared_ptr<T> and store the returned T* somewhere. Or, more subtly, you can write a function that takes a T& and then stores that reference somewhere else. Then you pass *t (where t is a shared_ptr<T>) to that method and you've blown it.
Both would be really stupid things to do and any non-newbie programmer in C++ knows better.