int ref;
seems problematic. Why would we want a negative number of references? What about signed integer overflow? (In a common case, we'll soon end up at 0 again, and delete an in-use object - this is something that has led to real bugs in prominent software, including the Linux kernel).
I recommend std::size_t as a better choice for counting references.
It seems wasteful (of developer time) for each ref-counted class to have to implement add_ref() and release() - consider providing a suitable base class that can be used (either as a mix-in base if your coding standards permit multiple inheritance, or as a CRTP wrapper).
operator=() are declared noexcept but call T::add_ref() and/or T::release() and we don't know whether they might throw. Given that the destructor calls release(), we should either insist that T::release() be noexcept, or catch whatever it throws.