| <?php |
| $title="RefPtr Basics"; |
| include("../header.inc"); |
| ?> |
| |
| <style type="text/css"> |
| .code { |
| background-color: #eee; |
| padding: 1em; |
| margin-left: 2em; |
| margin-right: 2em; |
| overflow-x: auto; |
| } |
| .comment .function, .class, .variable { |
| font-style: italic; |
| } |
| </style> |
| |
| <h1><span class="class">RefPtr</span> Basics</h1> |
| <div>Darin Adler</div> |
| <div>Version 5, 2015-04-19</div> |
| |
| <h2>History</h2> |
| |
| <p>Many objects in WebKit are reference counted. The pattern is that classes have |
| member functions named <span class="function">ref</span> and <span class="function">deref</span> |
| that increment and decrement a reference count. When the <span class="function">deref</span> function is called |
| on an object with a reference count of 1, the object is deleted. Many classes in WebKit implement |
| this pattern by deriving from the <span class="class">RefCounted</span> class template.</p> |
| |
| <p>Back in 2005, we discovered that there were many memory leaks, especially in HTML |
| editing code, caused by misuse of <span class="function">ref</span> and |
| <span class="function">deref</span> calls. |
| We decided to use smart pointers to mitigate the problem. Early experiments showed that |
| smart pointers led to additional manipulation of reference counts that hurt performance. |
| For example, for a function that took a smart pointer as an argument and returned that same smart |
| pointer as a return value, 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.</p> |
| |
| <p>We solved that problem in 2005 with a set of smart pointer class templates. C++ move semantics, |
| introduced in C++11, made it possible to streamline those class templates without |
| reintroducing reference count churn.</p> |
| |
| <p>Later, in 2013, we noticed that our use of pointers in general, and smart pointers in particular, |
| was causing a proliferation of null checks and uncertainty about what can be null. |
| We started using references rather than pointers wherever possible in WebKit code.</p> |
| |
| <p>Maciej Stachowiak created the class template, <span class="class">RefPtr</span>, |
| that implements WebKit’s intrusive reference counting, and we have since adapted it so that it |
| works well with move semantics. Andreas Kling created a related class template, |
| <span class="class">Ref</span>, which works with RefPtr and provides clarity and |
| even greater efficiency when dealing with |
| reference counted objects in contexts where there is no need for a null pointer.</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 { nullptr }; |
| } |
| |
| Document::~Document() |
| { |
| if (m_title) |
| m_title->deref(); |
| } |
| |
| void Document::setTitle(Title* title) |
| { |
| if (title) |
| title->ref(); |
| if (m_title) |
| m_title->deref(); |
| m_title = title; |
| }</pre> |
| |
| <h2><span class="class">RefPtr</span></h2> |
| |
| <p><span class="class">RefPtr</span> is a smart pointer class template 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* title) |
| { |
| m_title = title; |
| }</pre> |
| |
| <p>Functions that take take ownership of reference counted arguments can lead to reference count churn.</p> |
| |
| <pre class="code"><span class="comment">// example, not preferred style |
| |
| RefPtr<Title> untitledTitle = titleFactory().createUniqueUntitledTitle(); |
| |
| document.setTitle(untitledTitle);</pre> |
| |
| <p>The title starts with a reference count of 1. The <span class="function">setTitle</span> function stores it in the data member, |
| and the reference count is incremented to 2. Then the local variable <span class="variable">untitledTitle</span> goes out of |
| scope and the reference count is decremented back to 1.</p> |
| |
| <p>The way to define a function that takes ownership of an object is to use an rvalue reference.</p> |
| |
| <pre class="code"><span class="comment">// preferred style</span> |
| |
| class Document { |
| <span class="comment">...</span> |
| RefPtr<Title> m_title; |
| } |
| |
| void Document::setTitle(RefPtr<Title>&& title) |
| { |
| m_title = WTF::move(title); |
| } |
| |
| <span class="comment">...</span> |
| |
| RefPtr<Title> untitledTitle = titleFactory().createUniqueUntitledTitle(); |
| |
| document.setTitle(WTF::move(untitledTitle));</pre> |
| |
| <p>The title makes it all the way into the data member with a reference count of 1; |
| it’s never incremented or decremented.</p> |
| |
| <p>Note the use of <span class="function">WTF::move</span> |
| instead of <span class="function">std::move</span>. |
| The WTF version adds a couple of compile time checks to catch common errors, and should be |
| used throughout the WebKit project in place of <span class="function">std::move</span>.</p> |
| |
| <h2><span class="class">Ref</span></h2> |
| |
| <p><span class="class">Ref</span> is like <span class="class">RefPtr</span>, except that it |
| acts like a reference rather than a pointer; it doesn’t have a null value.</p> |
| |
| <p><span class="class">Ref</span> works particularly well with return values; it’s often |
| straightforward to be sure that a newly created object will never be null.</p> |
| |
| <pre class="code"><span class="comment">// preferred style</span> |
| |
| Ref<Title> TitleFactory::createUniqueUntitledTitle() |
| { |
| return createTitle("untitled " + m_nextAvailableUntitledNumber++); |
| }</pre> |
| |
| <p>Using <span class="class">Ref</span> helps makes it clear to the caller that this function will never return null.</p> |
| |
| <h2>Mixing with raw pointers</h2> |
| |
| <p>The <span class="class">RefPtr</span> class mixes with raw pointers much as the smart |
| pointers in the C++ standard library, such as <span class="class">std::unique_ptr</span>, do.</p> |
| |
| <p>When using a <span class="class">RefPtr</span> to call a function that takes a raw pointer, |
| use the <span class="function">get</span> function.</p> |
| |
| <pre class="code">printNode(stderr, a.get());</pre> |
| |
| <p>With a <span class="class">Ref</span>, the <span class="function">get</span> function |
| produces a raw reference, and the <span class="function">ptr</span> function produces a raw pointer.</p> |
| |
| <pre class="code">printString(stderr, a.get().caption()); |
| printNode(stderr, a.ptr());</pre> |
| |
| <p>Many operations can be done on a <span class="class">RefPtr</span> |
| directly, without resorting to an explicit <span class="function">get</span> call.</p> |
| |
| <pre class="code">Ref<Node> a = createSpecialNode(); |
| RefPtr<Node> b = findNode(); |
| Node* c = getOrdinaryNode(); |
| |
| <span class="comment">// the * operator</span> |
| *b = value; |
| |
| <span class="comment">// the -> operator</span> |
| a->clear(); |
| b->clear(); |
| |
| <span class="comment">// null check in an if statement</span> |
| if (b) |
| log("not empty"); |
| |
| <span class="comment">// the ! operator</span> |
| if (!b) |
| log("empty"); |
| |
| <span class="comment">// the == and != operators, mixing with raw pointers</span> |
| if (b == c) |
| log("equal"); |
| if (b != c) |
| log("not equal"); |
| |
| <span class="comment">// some type casts</span> |
| RefPtr<DerivedNode> d = static_pointer_cast<DerivedNode>(d);</pre> |
| |
| <p>Normally, <span class="class">RefPtr</span> enforces a simple rule; it always |
| balances <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 start with 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>In the rare case where we have a need to transfer from a <span class="class">RefPtr</span> |
| to a raw pointer without changing the reference count, use the |
| <span class="function">leakRef</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.leakRef();</pre> |
| |
| <h2>RefPtr and new objects</h2> |
| |
| <p>New objects of classes that make use of the <span class="class">RefCounted</span> class template |
| are created with a reference count |
| of 1. The best programming idiom to use is to put such objects right into a |
| <span class="class">Ref</span> to make it impossible to forget to deref the object when done with |
| it. This means that anyone calling new on such an object should immediately |
| call adoptRef. In WebKit we use functions named create instead of direct calls |
| to new for these classes.</p> |
| |
| <pre class="code"><span class="comment">// preferred style</span> |
| |
| Ref<Node> Node::create() |
| { |
| return adoptRef(*new Node); |
| } |
| |
| Ref<Node> e = Node::create();</pre> |
| |
| <p>Because of the way <span class="function">adoptRef</span> is implemented, |
| this is an efficient idiom. |
| The object starts with a reference count of 1 and no code is generated to |
| examine or modify the reference count.</p> |
| |
| <pre class="code"><span class="comment">// preferred style</span> |
| |
| Ref<Node> createSpecialNode() |
| { |
| Ref<Node> a = Node::create(); |
| a->setCreated(true); |
| return a; |
| } |
| |
| Ref<Node> b = createSpecialNode();</pre> |
| |
| <p>The node object is put into a <span class="class">Ref</span> by a call |
| to <span class="function">adoptRef</span> inside <span class="function">Node::create</span>, |
| then passes into <span class="variable">a</span> and is passed into |
| <span class="variable">b</span>, all without touching the reference count.</p> |
| |
| <p>The <span class="class">RefCounted</span> class implements a runtime check |
| so we get an assertion failure if we create an object and call <span class="function">ref</span> |
| or <span class="function">deref</span> without first calling <span class="function">adoptRef</span>.</p> |
| |
| <h2>Guidelines</h2> |
| |
| <p>We’ve developed these guidelines for use of <span class="class">RefPtr</span> |
| and <span class="class">Ref</span> in WebKit code.</p> |
| |
| <h3>Local variables</h3> |
| <ul> |
| <li>If ownership and lifetime are guaranteed, a local variable can be a raw reference or pointer.</li> |
| <li>If the code needs to hold ownership or guarantee lifetime, a local variable should |
| be a <span class="class">Ref</span>, or if it can be null, a <span class="class">RefPtr</span>.</li> |
| </ul> |
| |
| <h3>Data members</h3> |
| <ul> |
| <li>If ownership and lifetime are guaranteed, a data member can be a raw reference or pointer.</li> |
| <li>If the class needs to hold ownership or guarantee lifetime, the data member should |
| be a <span class="class">Ref</span> or <span class="class">RefPtr</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 reference or raw pointer.</li> |
| <li>If a function does take ownership of an object, the argument should be a <span class="class">Ref&&</span> |
| or a <span class="class">RefPtr&&</span>. This includes many setter functions. |
| </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 reference or 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">Ref</span> or <span class="class">RefPtr</span>.</li> |
| </ul> |
| |
| <h3>New objects</h3> |
| <ul> |
| <li>New objects should be put into a <span class="class">Ref</span> as soon as possible |
| after creation to allow the smart pointers to do all reference counting automatically.</li> |
| <li>For <span class="class">RefCounted</span> objects, the above should be done with the |
| <span class="function">adoptRef</span> function.</li> |
| <li>Best idiom is to use a private constructor and a public |
| <span class="function">create</span> function that |
| returns a <span class="class">Ref</span>.</li> |
| </ul> |
| |
| <h2>Pitfalls</h2> |
| |
| <h3>PassRefPtr</h3> |
| <p>Programmers who worked on WebKit before C++11 are familiar with a class template called PassRefPtr |
| (soon to be renamed to DeprecatedPassRefPtr) and you will see it in older WebKit code.</p> |
| <ul> |
| <li>Any function result or local variable of type PassRefPtr should be replaced with one of type RefPtr or Ref.</li> |
| <li>Any argument of type PassRefPtr should be replaced with one of type RefPtr&& or Ref&&.</li> |
| <li>Code calling RefPtr::release to turn a RefPtr into a PassRefPtr should instead call WTF::move.</li> |
| </ul> |
| |
| <h3>Common mistakes</h3> |
| <ul> |
| <li>Giving a function argument a type of Ref, RefPtr, Ref&&, or RefPtr&& |
| when it should instead be a raw reference or raw pointer. A function that sometimes takes ownership |
| can work just fine with a raw reference or raw pointer. The rvalue reference form is appropriate |
| when passing ownership is the primary way the function is used and is the case that needs to be optimized. |
| Not all setters need to take an rvalue reference.</li> |
| <li>Forgetting to call WTF::move can result in unnecessary reference count churn.</li> |
| </ul> |
| |
| <h2>Improving this document</h2> |
| |
| <p>We should add answers to any frequently asked questions are not covered by this document. |
| One or more of the following topics could also be covered by this document.</p> |
| |
| <ul> |
| |
| <li>copyRef</li> |
| <li>releaseNonNull</li> |
| |
| <li>How this works when these are stored in collections such as vectors and hash maps.</li> |
| |
| <li>Better explanation of when WTF::move is needed and not needed.</li> |
| |
| <li>The “protector” idiom, where a local <span class="class">Ref</span> variable is used to keep an object alive.</li> |
| |
| <li>Perils of programming with <span class="class">TreeShared</span>. |
| (Or after we merge <span class="class">TreeShared</span> into <span class="class">Node</span>, |
| the perils of programming with <span class="class">Node</span>).</li> |
| |
| <li>Our desire to eliminate <span class="class">TreeShared</span> and instead have |
| nodes hold a reference to their first child and next sibling.</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 WebKit intrusive reference counting with other schemes such as the |
| external reference counting in <span class="class">std::shared_ptr</class>.</li> |
| |
| <li>Guidelines for use of <span class="class">std::unique_ptr</span> and <span class="class">std::make_unique</span>.</li> |
| |
| <li>The <span class="class">RetainPtr</span> class template.</li> |
| |
| </ul> |
| |
| <p>If you have any comments on the above or other ideas about improving the clarity, |
| scope, or presentation, please send mail to the <a href="/contact.html">WebKit mailing list</a>.</p> |
| |
| <?php |
| include("../footer.inc"); |
| ?> |