like songs and courses: it's difficult to guarantee that all references
to them are updated if they're deleted or reallocated, which is a brittleness
that leads to obscure bugs.
A general fix for this is to avoid storing pointers to objects, and
to use IDs instead; for example, SongID to reference a song (which
tags by directory). This leads to an efficiency problem: searching
a map<RString> is much more expensive. We need a robust way to
cache the results.
Implement CachedObject<T>, CachedObjectPointer<T>. This implements
caching pointers to objects, negative caching, clearing cache when objects
are deleted, and clearing negative cache when objects are created.