| <?php |
| $title="RefPtr and PassRefPtr Basics"; |
| include("../header.inc"); |
| ?> |
| |
| <style type="text/css"> |
| .code { |
| background-color: #eee; |
| padding: 1em; |
| margin-left: 2em; |
| margin-right: 2em; |
| overflow-x: auto; |
| } |
| .comment { |
| font-style: italic; |
| } |
| p .function, p .class, p .variable, li .function, li .class, li .variable { |
| font-style: italic; |
| } |
| </style> |
| |
| <h1><span class="class">RefPtr</span> and <span class="class">PassRefPtr</span> Basics</h1> |
| <div>Darin Adler</div> |
| <div>first draft, 2007-03-24</div> |
| |
| <h2>History</h2> |
| |
| <p>Many objects in WebKit are reference counted. The pattern used is that classes have |
| member functions <span class="function">ref</span> and <span class="function">deref</span> |
| that increment and decrement the reference count. Each call to <span class="function">ref</span> |
| has to be matched by a call to <span class="function">deref</span>. When the reference count hits 0, |
| the object is deleted. Many of these classes create new objects with a reference count of 0; this |
| is referred to as the floating state. An object in floating state must have <span class="function">ref</span> and then |
| <span class="function">deref</span> called on it before it will be deleted. Many classes in WebCore implement this by |
| inheriting from the <span class="class">Shared</span> class template.</p> |
| |
| <p>Back in 2005, we discovered that there were many memory leaks, especially in WebCore |
| editor code, caused either by mismatches of <span class="function">ref</span> and |
| <span class="function">deref</span> calls or by objects that were created with |
| <span class="function">new</span> that never got a <span class="function">ref</span> |
| call at all and remained in the floating state.</p> |
| |
| <p>We decided that we’d like |
| to use smart pointers to mitigate the problem. However, some early experiments showed that |
| smart pointers led to additional manipulation of reference counts that hurt performance. |
| For example, if a function took a smart pointer as a parameter and returned that same smart |
| pointer as a return value, just passing the parameter and returning the value would increment |
| and then decrement the reference count two to four times |
| as the object moved from one smart pointer to another. So we looked for an |
| idiom that would let us use smart pointers and avoid this reference count churn.</p> |
| |
| <p>The inspiration for a solution came from the C++ standard class template <span class="class">auto_ptr</span>. |
| These objects implement a model where assignment is transfer of ownership. When you assign |
| from one <span class="class">auto_ptr</span> to another, the donor becomes 0.</p> |
| |
| <p>Maciej Stachowiak devised a pair of class templates, <span class="class">RefPtr</span> |
| and <span class="class">PassRefPtr</span>, that implement this scheme |
| for WebCore’s intrusive reference counting.</p> |
| |
| <h2>Raw pointers</h2> |
| |
| <p>When discussing smart pointers such as the <span class="class">RefPtr</span> |
| class template we use the term raw pointer to refer to the C++ language’s built in pointer type. |
| Here’s the canonical setter function, written with raw pointers:</p> |
| |
| <pre class="code"><span class="comment">// example, not preferred style</span> |
| |
| class Document { |
| <span class="comment">[...]</span> |
| Title* m_title; |
| } |
| |
| Document::Document() |
| : m_title(0) |
| { |
| } |
| |
| Document::~Document() |
| { |
| if (m_title) |
| m_title->deref(); |
| } |
| |
| void Document::setTitle(Title* t) |
| { |
| if (t) |
| t->ref(); |
| if (m_title) |
| m_title->deref(); |
| m_title = t; |
| }</pre> |
| |
| <h2><span class="class">RefPtr</span></h2> |
| |
| <p><span class="class">RefPtr</span> is a simple smart pointer class that calls <span class="function">ref</span> |
| on incoming values and |
| <span class="function">deref</span> on outgoing values. |
| <span class="class">RefPtr</span> works on any object with both a <span class="function">ref</span> and |
| a <span class="function">deref</span> member function. |
| Here’s the setter function example, written with <span class="class">RefPtr</span>:</p> |
| |
| <pre class="code"><span class="comment">// example, not preferred style</span> |
| |
| class Document { |
| <span class="comment">[...]</span> |
| RefPtr<Title> m_title; |
| } |
| |
| void Document::setTitle(Title* t) |
| { |
| m_title = t; |
| }</pre> |
| |
| <p>Use of <span class="class">RefPtr</span> alone can lead to reference count churn.</p> |
| |
| <pre class="code"><span class="comment">// example, not preferred style</span> |
| |
| RefPtr<Node> createSpecialNode() |
| { |
| RefPtr<Node> a = new Node; |
| a->setSpecial(true); |
| return a; |
| } |
| |
| RefPtr<Node> b = createSpecialNode();</pre> |
| |
| <p>The node object starts with a reference count of 0. When it’s assigned to <span class="variable">a</span>, |
| the reference count is incremented to 1. The reference count is incremented to 2 to |
| create the return value, then decremented back to 1 when <span class="variable">a</span> is destroyed. |
| Then the reference count is incremented to 2 to create <span class="variable">b</span>, and then decremented back |
| to 1 when the return value of <span class="function">createSpecialNode</span> is destroyed.</p> |
| |
| <p>(This analysis ignores the possibility that the compiler might implement the |
| <a href="http://www.awprofessional.com/articles/article.asp?p=25033&seqNum=3&rl=1">return value optimization</a>. |
| If the compiler does, some of the reference count churn may be mitigated.)</p> |
| |
| <p>The overhead of reference count churn is even greater when both function arguments and return |
| values are involved. The solution is <span class="class">PassRefPtr</span>.</p> |
| |
| <h2><span class="class">PassRefPtr</span></h2> |
| |
| <p><span class="class">PassRefPtr</span> is like <span class="class">RefPtr</span> with a difference. |
| When you copy a <span class="class">PassRefPtr</span> or |
| assign the value of a <span class="class">PassRefPtr</span> to a <span class="class">RefPtr</span> or |
| another <span class="class">PassRefPtr</span>, the original |
| pointer value is set to 0; the operation is done without any change to the reference count. |
| Let’s take a look at a new version of our example:</p> |
| |
| <pre class="code"><span class="comment">// example, not preferred style</span> |
| |
| PassRefPtr<Node> createSpecialNode() |
| { |
| PassRefPtr<Node> a = new Node; |
| a->setSpecial(true); |
| return a; |
| } |
| |
| RefPtr<Node> b = createSpecialNode();</pre> |
| |
| <p>The node object starts with a reference count of 0. When it’s assigned to <span class="variable">a</span>, |
| the reference count is incremented to 1. Then <span class="variable">a</span> gets set to 0 when the return |
| value <span class="class">PassRefPtr</span> is created. Then the return value is set to 0 when |
| <span class="variable">b</span> is created.</p> |
| |
| <p>However, as the Safari team learned when we started programming with <span class="class">PassRefPtr</span>, |
| the rule that a pointer becomes 0 when it’s assigned to another variable can easily lead to mistakes.</p> |
| |
| <pre class="code"><span class="comment">// example, not preferred style</span> |
| |
| static RefPtr<Ring> g_oneRingToRuleThemAll; |
| |
| void finish(PassRefPtr<Ring> ring) |
| { |
| g_oneRingToRuleThemAll = ring; |
| <span class="comment">...</span> |
| ring->wear(); |
| }</pre> |
| |
| <p>By the time <span class="function">wear</span> is called, <span class="variable">ring</span> |
| is already 0. To avoid this, we recommend <span class="class">PassRefPtr</span> only for |
| function argument and result types, copying arguments into <span class="class">RefPtr</span> |
| local variables.</p> |
| |
| <pre class="code">static RefPtr<Ring> g_oneRingToRuleThemAll; |
| |
| void finish(PassRefPtr<Ring> prpRing) |
| { |
| RefPtr<Ring> ring = prpRing; |
| g_oneRingToRuleThemAll = ring; |
| <span class="comment">...</span> |
| ring->wear(); |
| }</pre> |
| |
| <h2>Mixing <span class="class">RefPtr</span> and <span class="class">PassRefPtr</span></h2> |
| |
| <p>Since we recommend use of <span class="class">RefPtr</span> in all cases except when passing arguments to or |
| returning values from a function, there will be times when you have a <span class="class">RefPtr</span> |
| and wish to transfer ownership as <span class="class">PassRefPtr</span> does. |
| <span class="class">RefPtr</span> has a member function named |
| <span class="function">release</span> which does the trick. It sets the value of the original |
| <span class="class">RefPtr</span> to 0 and constructs a <span class="class">PassRefPtr</span>, without |
| changing reference counts.</p> |
| |
| <pre class="code">PassRefPtr<Node> createSpecialNode() |
| { |
| RefPtr<Node> a = new Node; |
| a->setCreated(true); |
| return a.release(); |
| } |
| |
| RefPtr<Node> b = createSpecialNode();</pre> |
| |
| <p>This keeps the efficiency of <span class="class">PassRefPtr</span> while reducing the chance |
| that its relatively tricky semantics will cause problems.</p> |
| |
| <h2>Mixing with raw pointers</h2> |
| |
| <p>When using a <span class="class">RefPtr</span> to call a function that takes a raw pointer, |
| use <span class="function">get</span>.</p> |
| |
| <pre class="code">printNode(stderr, a.get());</pre> |
| |
| <p>However, there are operations that can be done on a <span class="class">RefPtr</span> |
| or <span class="class">PassRefPtr</span> directly, without resorting to an explicit <span class="function">get</span> call.</p> |
| |
| <pre class="code">RefPtr<Node> a = createSpecialNode(); |
| Node* b = getOrdinaryNode(); |
| |
| <span class="comment">// the * operator</span> |
| *a = value; |
| |
| <span class="comment">// the -> operator</span> |
| a->clear(); |
| |
| <span class="comment">// null check in an if statement</span> |
| if (a) |
| log("not empty"); |
| |
| <span class="comment">// the ! operator</span> |
| if (!a) |
| log("empty"); |
| |
| <span class="comment">// the == and != operators, mixing with raw pointers</span> |
| if (a == b) |
| log("equal"); |
| if (a != b) |
| log("not equal"); |
| |
| <span class="comment">// some type casts</span> |
| RefPtr<DerivedNode> d = static_pointer_cast<DerivedNode>(a);</pre> |
| |
| <p>Normally, <span class="class">RefPtr</span> and <span class="class">PassRefPtr</span> |
| enforce a simple rule; they always balance <span class="function">ref</span> and |
| <span class="function">deref</span> calls, guaranteeing a programmer can’t miss a |
| <span class="function">deref</span>. But in the case where we have a raw pointer, |
| already have a reference count, and want to transfer ownership the |
| <span class="function">adoptRef</span> function should be used.</p> |
| |
| <pre class="code"><span class="comment">// warning, requires a pointer that already has a ref</span> |
| RefPtr<Node> node = adoptRef(rawNodePointer);</pre> |
| |
| <p>To transfer from a <span class="class">RefPtr</span> to a raw pointer without |
| changing the reference count, <span class="class">PassRefPtr</span> provides the |
| <span class="function">releaseRef</span> function.</p> |
| |
| <pre class="code"><span class="comment">// warning, results in a pointer that must get an explicit deref</span> |
| RefPtr<Node> node = createSpecialNode(); |
| Node* rawNodePointer = node.release().releaseRef();</pre> |
| |
| <p>Since <span class="function">releaseRef</span> is rarely used, it’s provided only in the |
| <span class="class">PassRefPtr</span> class, hence the need to call <span class="function">release</span>, |
| then <span class="function">releaseRef</span>. If we find this is used often we could |
| provide <span class="function">releaseRef</span> for <span class="class">RefPtr</span> too.</p> |
| |
| <h2>Guidelines</h2> |
| |
| <p>We’ve developed these guidelines for use of <span class="class">RefPtr</span> |
| and <span class="class">PassRefPtr</span> in WebKit code.</p> |
| |
| <h3>Local variables</h3> |
| <ul> |
| <li>If ownership and lifetime are guaranteed, a local variable can be a raw pointer.</li> |
| <li>If the code needs to hold ownership or guarantee lifetime, a local variable should |
| be a <span class="class">RefPtr</span>.</li> |
| <li>Local variables should never be <span class="class">PassRefPtr</span>.</li> |
| </ul> |
| |
| <h3>Data members</h3> |
| <ul> |
| <li>If ownership and lifetime are guaranteed, a data member can be a raw pointer.</li> |
| <li>If the class needs to hold ownership or guarantee lifetime, the data member should |
| be a <span class="class">RefPtr</span>.</li> |
| <li>Data members should never be <span class="class">PassRefPtr</span>.</li> |
| </ul> |
| |
| <h3>Function arguments</h3> |
| <ul> |
| <li>If a function does not take ownership of an object, the argument should be a raw pointer.</li> |
| <li>If a function does take ownership of an object, the argument should be a <span class="class">PassRefPtr</span>. |
| This includes most setter functions. |
| Unless the use of the argument is very simple, the argument should be transferred to a |
| <span class="class">RefPtr</span> at the start of the function; the argument can be named with |
| a “prp” prefix in such cases.</li> |
| </ul> |
| |
| <h3>Function results</h3> |
| <ul> |
| <li>If a function’s result is an object, but ownership is not being transferred, the result |
| should be a raw pointer. This includes most getter functions.</li> |
| <li>If a function’s result is a new object or ownership is being transferred for any other |
| reason, the result should be a <span class="class">PassRefPtr</span>. |
| Since local variables are typically <span class="class">RefPtr</span>, it’s common to call |
| <span class="function">release</span> in the return statement to transfer the |
| <span class="class">RefPtr</span> to the <span class="class">PassRefPtr</span>.</li> |
| </ul> |
| |
| <h3>New objects</h3> |
| <ul> |
| <li>New objects should be put into a <span class="class">RefPtr</span> as soon as possible |
| after creation to avoid possibly leaking an object while it’s in a floating state.</li> |
| <li>Best idiom is to use a private constructor and have a public factory function that |
| returns a <span class="class">PassRefPtr</span>.</li> |
| </ul> |
| |
| <h2>Improving this document</h2> |
| |
| <p>What frequently asked questions are not covered by this document?</p> |
| |
| <p>Which of these topics should also be covered by this document?</p> |
| |
| <ul> |
| |
| <li>The “protector” idiom, where a local RefPtr variable is used to keep an object alive.</li> |
| |
| <li>Perils of programming with floating objects.</li> |
| |
| <li>Why we should use create functions that return <span class="class">PassRefPtr</span> |
| rather than use <span class="function">new</span> directly.</li> |
| |
| <li>Perils of programming with <span class="class">TreeShared</span>.</li> |
| |
| <li>Our desire to rename <span class="class">Shared</span> to <span class="class">RefCounted</span>.</li> |
| |
| <li>Our desire to eliminate <span class="class">TreeShared</span> and instead have |
| <span class="variable">m_firstChild</span> and <span class="variable">m_next</span> be |
| <span class="class">ListRefPtr</span> or the equivalent.</li> |
| |
| <li>How we we mix reference counting with garbage collection to implement the DOM |
| and the JavaScript and Objective-C DOM bindings.</li> |
| |
| <li>Comparison of our intrusive reference counting with other schemes such as the |
| external reference counting in Boost <span class="class">shared_ptr</class>.</li> |
| |
| <li>The <span class="class">OwnPtr</span> class template, and how |
| <span class="class">auto_ptr</span> functions as a <span class="class">PassOwnPtr</span>.</li> |
| |
| <li>The <span class="class">OwnArrayPtr</span> class template, |
| and the lack of a <span class="class">PassOwnArrayPtr</span>.</li> |
| |
| <li>The <span class="class">RetainPtr</span> class template, |
| and the lack of a <span class="class">PassRetainPtr</span>.</li> |
| |
| <li>The <span class="class">DocPtr</span> class template.</li> |
| |
| <li>The <span class="class">ListRefPtr</span> class template.</li> |
| |
| </ul> |
| |
| <p>Any other ideas about improving the clarity, scope, or presentation?</p> |
| |
| <?php |
| include("../footer.inc"); |
| ?> |