This is actually a bit more complicated: the mechanism behind shared_ptr
is pretty complicated.
First, let's prove that there are no special permissions granted to shared_ptr
:
int main() { A* a = new B(); std::shared_ptr<A> p(a);
This will result in an error because destructor A
not available. Interestingly, an error occurs at the point of construction, which is the key ...
So what is the magic behind shared_ptr
?
Inside, a shared_ptr
stores much more than a simple pointer and reference count. A shared_ptr
built with a deleter
responsible for destroying an instance of an object. Where the design really shines, it is that this deleter
is created in the constructor and therefore can know more information about the type than the bare type shared_ptr
allows.
Simplified demo:
template <typename T> struct shared_holder { typedef void (*Disposer)(T*); explicit shared_holder_base(T* t, Disposer d): _ptr(t), _disposer(d) {} void dispose() { _disposer(_ptr); _ptr = 0; } T* _ptr; Disposer _disposer; }; template <typename U, typename T> void dispose(T* t) { delete static_cast<U*>(t); } template <typename T> class shared_ptr { typedef shared_holder<T> holder; public: shared_ptr(): _holder(0), _ptr(0) {} template <typename U> explicit shared_ptr(U* u): _holder(new holder(u, dispose<U, T>)), _ptr(_holder->_ptr) {} private: holder* _holder; T* _ptr; };
The key understanding is that the removal tool is created from a static type known to the constructor; that's why:
shared_ptr<A>(new B)
worksA* a = new B; shared_ptr<A>(a)
A* a = new B; shared_ptr<A>(a)
not
You can read the Boost headers, the hardware behind shared_ptr
pretty interesting.
As an exercise for the reader, why does shared_ptr<T>
have the _ptr
member?
source share