We're still going to need two objects, one a base object and one a pointer object. If we use raw pointers, the reference count will not be incremented and decremented properly, and we need the reference count to reliably be equal to the number of pointers extant. Therefore, the pointer needs to have its own copy constructor, copy assignment operator, and destructor, which will call the appropriate increment and decrement methods (the decrement method to include the deletion as a special case). If we keep the reference count with the object instead of with the pointer, we can keep the pointer size down without indirection.
This is no more complicated than what has to be done with shared_ptr. And you are confused, you can use raw pointers all you want, as long as you know there is a shared_ptr pointing at the object. This happens in many cases.
We need to document heavily that IRefCount (or something more according to C++ naming) is to be inherited virtually, as otherwise we could have more than one reference count if we add it to multiple levels of a class hierarchy. (C++ multiple inheritance can be tricky to get right.)
So, we've got the pointer object, which will contain the pointer and have some attached functionality, and the reference count mixin. This works as long as we can easily modify the class structure, but it does require a fairly sophistication serialization/deserialization system to keep the modified and unmodified objects in sync. In addition, since it changes the memory layout of a class, it can lead to slow compiles.
It's not a "mixin". It is a base class. This avoids your supposed problems.
With this, we also don't get weak_ptr functionality. A shared_ptr object has a shared pointer count and a weak pointer count. This makes it possible, for example, to have a circular list that can be destructed: have one link be a weak_ptr and everything else a shared_ptr. The object itself is destructed when the shared pointer count goes to zero, and the shared_ptr object when both go to zero. (A weak_ptr does nothing on its own, but can be converted to a shared_ptr if the target object is still there.)
You can implement weak_ptr in EXACTLY the same way make_shared does it. The object is destroyed but the memory is not freed until the weak_ptr count goes to zero. In fact it is fairly easy to have "an object that supports weak_ptr" be a different base class than the plain refcounted object, thus you don't pay for the weak_ptr overhead on every pointer (though you can't make a weak_ptr unless the object is derived from the correct base class).
I don't see this as being easier than shared_ptr, although it is superior for some purposes.
It is enormously easier when you have to do the equivalent of make_shared_from_this (or whatever they called it), and to avoid constructor shenanigans so that the user has to call make_shared and not construct raw objects. The implementation is about the same as shared_ptr.
Boost called this an "intrusive pointer" but they did not support weak pointers. That could be done with a few extra calls. It was a bit ugly as they tried to not define the base class (instead it called functions that the class defined to inc/dec the ref count), I think insisting that everything be based on a refcounted base class would work just fine.