Practical uses that involve cycles are quite a few kinds of graphs. A trivial snippet (though one that's unlikely to happen in real life) would be something like:
struct node {
node *next;
};
int create_cycle() {
node *a = new node;
a.next = a;
}
After create_cycle returns, the node we just allocated contains a reference to itself, but there's no other point to it, so a reference counter won't collect it even though it's garbage.
Chris Jester-Young has already dealt with cycle breaking with smart pointers from a practical viewpoint. He didn't go into any real detail about how it works internally though.
A weak_ptr is sort of a doubly-indirect pointer. I.e. the weak_ptr doesn't give acces directly with an object. Instead, to get to the object, you have to convert the weak_ptr to a shared_ptr, then use that to get to the object -- but the attempt to convert the weak_ptr to a shared_ptr will only succeed if there's still at least one other shared_ptr to the managed object (so the object has a nonzero reference count and still exists).
As such, a weak_ptr gives you access to an object as long as it exists, but "knows" when the object ceases to exist and doesn't give you access to the (now freed) memory where the object used to be if the object has been destroyed.
Avoiding cycles depends on the sorts of things you're working with. If you deal with graphs a lot (for one example) they're often almost impossible to avoid, simply because quite a few things you model have cycles. Otherwise, well...it depends. I'd guess a fair number of developers have gone for entire careers without ever having to create a linked structure that contains a cycle. Others probably do it several times in an average week.
As far as other smart pointers go, as noted above the weak_ptr type works in conjunction with the shared_ptr; you can use shared_ptr without ever using a weak_ptr, but to make much real use of a weak_ptr at some point you have to convert it to a shared_ptr.