Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><code>shared_ptr</code> must manage a reference counter and the carrying of a deleter functor that is deduced by the type of the object given at initialization.</p> <p>The <code>shared_ptr</code> class typically hosts two members: a <code>T*</code> (that is returned by <code>operator-&gt;</code> and dereferenced in <code>operator*</code>) and a <code>aux*</code> where <code>aux</code> is a inner abstract class that contains:</p> <ul> <li>a counter (incremented / decremented upon copy-assign / destroy)</li> <li>whatever is needed to make increment / decrement atomic (not needed if specific platform atomic INC/DEC is available)</li> <li>an abstract <code>virtual destroy()=0;</code></li> <li>a virtual destructor.</li> </ul> <p>Such <code>aux</code> class (the actual name depends on the implementation) is derived by a family of templatized classes (parametrized on the type given by the explicit constructor, say <code>U</code> derived from <code>T</code>), that add:</p> <ul> <li>a pointer to the object (same as <code>T*</code>, but with the actual type: this is needed to properly manage all the cases of <code>T</code> being a base for whatever <code>U</code> having multiple <code>T</code> in the derivation hierarchy)</li> <li>a copy of the <code>deletor</code> object given as deletion policy to the explicit constructor (or the default <code>deletor</code> just doing delete <code>p</code>, where <code>p</code> is the <code>U*</code> above)</li> <li>the override of the destroy method, calling the deleter functor.</li> </ul> <p>A simplified sketch can be this one:</p> <pre><code>template&lt;class T&gt; class shared_ptr { struct aux { unsigned count; aux() :count(1) {} virtual void destroy()=0; virtual ~aux() {} //must be polymorphic }; template&lt;class U, class Deleter&gt; struct auximpl: public aux { U* p; Deleter d; auximpl(U* pu, Deleter x) :p(pu), d(x) {} virtual void destroy() { d(p); } }; template&lt;class U&gt; struct default_deleter { void operator()(U* p) const { delete p; } }; aux* pa; T* pt; void inc() { if(pa) interlocked_inc(pa-&gt;count); } void dec() { if(pa &amp;&amp; !interlocked_dec(pa-&gt;count)) { pa-&gt;destroy(); delete pa; } } public: shared_ptr() :pa(), pt() {} template&lt;class U, class Deleter&gt; shared_ptr(U* pu, Deleter d) :pa(new auximpl&lt;U,Deleter&gt;(pu,d)), pt(pu) {} template&lt;class U&gt; explicit shared_ptr(U* pu) :pa(new auximpl&lt;U,default_deleter&lt;U&gt; &gt;(pu,default_deleter&lt;U&gt;())), pt(pu) {} shared_ptr(const shared_ptr&amp; s) :pa(s.pa), pt(s.pt) { inc(); } template&lt;class U&gt; shared_ptr(const shared_ptr&lt;U&gt;&amp; s) :pa(s.pa), pt(s.pt) { inc(); } ~shared_ptr() { dec(); } shared_ptr&amp; operator=(const shared_ptr&amp; s) { if(this!=&amp;s) { dec(); pa = s.pa; pt=s.pt; inc(); } return *this; } T* operator-&gt;() const { return pt; } T&amp; operator*() const { return *pt; } }; </code></pre> <p>Where <code>weak_ptr</code> interoperability is required a second counter (<code>weak_count</code>) is required in <code>aux</code> (will be incremented / decremented by <code>weak_ptr</code>), and <code>delete pa</code> must happen only when both the counters reach zero.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload