Unique pointers are a type of smart pointers.
The topic was about garbage collectors, and typically garbage collectors thread pointers as shared pointers. While unique pointers are also a type of smart pointers, they are significantly different then what garbage collectors do. So I specifically meant shared pointers when I was talking about it being an antipattern, as in most cases there is no such thing as shared ownership.
Smart pointers solve most the things you are complaining about. They declare the intent of ownership and usage, explicitly state the lifetime of the object, delete the object instantly (not seconds later), with far less risk than manual management, and keep things compact in terms of memory usage, without large performance hits.
I'm afraid you misunderstood the situation I was explaining. Those three type of smart pointers you mentioned (unique, shared and weak) are exactly the ones the lack the ability to maintain the class invariant when object B needs to have a reference to object A, but doesn't own it. Neither shared pointer (as B doesn't have ownership, not even shared ownership) or weak pointer (as these can expire, which according to the class invariant is not allowed) make this kind of relationship possible. Of course you can use a weak_ptr in B to A here, and assert if B wants to use the pointer but it's no longer there, but it's a pain in the ass to debug an assertion that triggers any given time after the class invariant was broken. Preferably you assert at the moment this happens, so at the moment A is deleted while there are still non-owning references to this A that cannot exist in a valid state without this reference.
So personally, I would make a difference between ownership (99% of the cases non-transferable and non-shared), weak references (that automatically turn to null if object is destroyed) and hard references (for objects that cannot exist without the object pointed to, but neither own it). This would be a much more powerful system then garbage collectors can offer, with immediate assertion on fatal errors rather then continuing with one or more objects in invalid state for some time until it crashes or starts displaying undefined behaviour. Which from experience I can tell is extremely painful to debug as there is no callstack going back to when the problem really happened if it may even have happened minutes ago.