A free-standing weak_ptr equivalent to handle lifetime of non-shared callback objects
I never saw a similar pattern so it was really interesting to understand your code !

First, about the name weak_ref, it implies that it has the syntax of a reference, but it is not the case (for instance, operator-&gt; is for pointers). I personnaly named it something like ptr_to_instance.

Then, it seems the weak_ref should not be used on its own, without calling enable_weak_ref::get_weak_ref(). So I will make the weak_ref constructor private, making enable_weak_ref a friend. I will put the weak_ref class inside enable_weak_ref :

template&lt;typename CRTP&gt;
class enable_weak_ref {
  public:
    class weak_ref { /**/ };
    /**/
};


So instead of weak_ref&lt;T&gt; we have enable_weak_ref&lt;T&gt;::weak_ref. I think it makes more understandable the use of these classes.

Also, because weak_ref should not modify the pointer in weak_data_, I would use std::shared_ptr&lt;T* const&gt; so it is clear that this pointer is for read-only use.

If you do not want to use std::shared_ptr, you should create a int* (counting references), a CRTP** (which will hold this or nullptr) in enable_weak_ref, and weak_ref should have a int* const and a CRTP const* const (const specifier shows that weak_ref is linked to only one enable_weak_ref and can not be changed).