BTW, the problems with thread registration you mention can be solved using cpu-local storage instead of thread-local. This can also save space usage and collection time since, assuming short lifetimes for guard objects, the total maximum number of guard objects that ever come into existence simultaneously is smaller.
In lots of practical scenarios though, hazard pointers aren't great for performance, since they require a Store|Load fence during every load operation (e.g. traversing linked list requires O(n) mfences). Alternatives like Fraser's epoch-based reclamation or quiescent state based reclamation often perform better in "real life". (Not to imply you're not familiar with this, haberman, but it's useful to document for other readers).