Okay, finally nailed it down.
It seems that sigc++ doesn't deal with reference parameters totally graciously; it was creating a copy of an SPObject & argument somewhere internally, causing equivalency tests further in to fail.
Actually this would have been caught a long time ago if SPObject had been given a private copy constructor (or at least not left with an implicit public one).
Rule of thumb with C++: if it's not a value class [a class in which binary copies of objects are interchangable], give it a private copy constructor like so:
class Foo { public: Foo(); ... private: Foo(Foo const &); // no copy };
You needn't actually define the copy constructor once you've declared it, as in this case it shouldn't be used.
If you don't do this, C++ will add a copy constructor for you that just does a binary copy, and all kinds of happy bugs like the one I just fixed can sneap up on youl.
In rare cases where you do need to give such classes real copy constructorsm, make sure that they're either explicit, or not public.
-mental