I don't know of a study on the additional cost due to non-invasive over invasive. But I would note that non-invasive seems to be universally recommended by the C++ experts. Of course, this may mean nothing! But the reasoning is pretty sound: if you need smart pointers, it's because you want a simpler way to implement object lifetime management instead of writing it by hand, so you are emphasising correctness and simplicity over performance, which is always a good idea until you have profiled a realistic model of your whole design.
It could well be that in a simplified test, non-invasive is twice as slow as invasive, and yet in a real program that does actual work, this speed difference is lost in the noise and becomes so insignificant you can't even measure it. This is quite a common phenomenon; the things you imagine are significant to performance very often aren't.
If you find a performance bottleneck, it's possible (likely?) that the work of maintaining the reference count itself (in both approaches) will have as much effect on performance as the extra indirection in the non-invasive approach. With raw pointers, the statement:
p1 = p2;
probably only needs to move a value between two CPU registers, after the optimiser has worked its magic. But if they are reference counting smart pointers, even with invasive it's like:
if (p1 != p2)
{
if ((p1 != 0) && (--(p1->count) == 0))
delete p1;
p1 = p2;
if (p1 != 0)
p1->count++;
}
This happens with every smart pointer argument passed to every function. So there are lots of extra accesses to potentially far-flung areas of memory, to raise and lower the count each time. And to be thread-safe, the increment and decrement-check operations have to be interlocked/atomic, which can have a severely negative effect on multiple cores.
I think of the "sweet spot" of C++ as being those situations where you don't need to manage wildly dynamic data structures like this. Instead you have a simple hierarchical pattern of object ownership, so there is an obvious single owner of each object, and the lifetime of data tends to follow the lifetime of function invocations (more often than not). You can then let the standard containers and the function call stack manage everything for you. This is emphasised in the forthcoming version of the language with rvalue references, unique_ptr, etc. which is all about transferring around the single-ownership of an object in an easy way. If you really need dynamic multi-owner lifetime management, true GC would be faster and easier to use correctly, but C++ isn't a very happy home for GC.
Another minor point: unfortunately "In non-invasive smart pointers, there is only one pointer that points to each Foo" is untrue. Inside Foo there is the this pointer that is a Foo * and so naked pointers can still be leaked out, often in quite hard-to-spot ways.