IMO, garbage collected languages have complementary problems to those in non-garbage-collected languages. For every issue, there is a non-GC-characteristic bug and a GC-characteristic bug - a non-GC programmer responsibility and a GC programmer responsibility.
GC programmers may believe that they are relieved of responsibility for freeing objects, but objects hold resources other than memory - resources that often need to be released in a timely way so that they can be acquired elsewhere - e.g. file handles, record locks, mutexes...
Where a non-GC programmer would have a dangling reference (and very often one that isn't a bug, since some flag or other state would mark it as not to be used), a GC programmer has a memory leak. Thus where the non-GC programmer is responsible for ensuring that free/delete is called appropriately, a GC programmer is responsible for ensuring that unwanted references are nulled or otherwise disposed of appropriately.
There is a claim in here that smart pointers don't deal with garbage cycles. This need not be true - there are reference counting schemes that can break cycles and which also ensure timely disposal of garbage memory, and at least one Java implementation used (and may still do) a reference counting scheme that could just as easily be implemented as a smart pointer scheme in C++.
Concurrent Cycle Collection in Reference Counted Systems
Of course this isn't normally done - partly because you may as well just use a GC language, but also partly IMO because it would break key conventions in C++. You see, lots of C++ code - including the standard library - relies heavily on the Resource Allocation Is Initialisation (RAII) convention, and that relies on reliable and timely destructor calls. In any GC that copes with cycles, you simply cannot have that. When breaking a garbage cycle, you cannot know which destructor to call first without any dependency issues - it may not even be possible, since there may be more cyclic dependencies than just memory references. The solution - in Java etc, there is no guarantee that finalizers will be called. Garbage collection only collects one very specific kind of garbage - memory. All other resources must be cleaned up manually, as they would have been in Pascal or C, and without the advantage of reliable C++-style destructors.
End result - a lot of cleanup that gets "automated" in C++ has to be done manually in Java, C# etc. Of course "automated" needs the quotes because the programmer is responsible for ensuring that delete is called appropriately for any heap-allocated objects - but then in GC languages, there are different but complementary programmer responsibilities. Either way, if the programmer fails to handle those responsibilities correctly, you get bugs.
Frankly, switching from non-GC to GC (or visa versa) is no magic wand. It may make the usual suspect problems go away, but that just means you need new skillsets to prevent (and debug) an whole new set of suspects.
A good programmer should get past the whos-side-are-you-on BS and learn to handle both.