|Probably this is the reason C++ still doesn't have a single concurrent data structure in its standard library and all the third party ones I've seen were subtly broken (e.g. leaking memory sometimes or having ABA problems, etc.).|
That's because all concurrent data structures designed for general use are fundamentally broken. For any nontrivial use you always end up needing an external lock, making the internal synchronization completely pointless.
This is why the only concurrent data structure I ever really use is a queue. Even then, checking the size of the queue is not directly possible; the size check needs to be combined with the pop operation by either making it blocking or somehow returning an error code along with the object.
Garbage collection does help in certain systems where cyclical references are unavoidable, although these situations are not that common in practice (how often do you really want your objects to pop out of existence because the last reference disappeared?). I rarely use shared_ptr as it is, and this is not because of the circular reference problem.
Memory fragmentation is not the huge issue GC fans want you to think it is. While the worst case is infinitely inefficient, real fragmentation is limited to wasting a fairly small percentage of the memory in use. Garbage collected languages are known for having very large memory overhead per allocation, so this only becomes a threat when using lots of large allocations (which aren't likely to fragment significantly by themselves). This leaves the speed penalty caused by fragmentation, until you realize that garbage collection is also slow, and again, fragmentation is not that common.
It all boils down to one simple reason why so many languages have garbage collection: it looks slightly easier. They get to claim that their language is SO much easier to use because you don't have to manage the memory, but GC does not extend to resources other than memory. A correctly written class in C++ knows how to clean up all of its resources even if the client fails to call cleanup methods. Good luck implementing this behavior in garbage collected languages.