blob: 8d52c9928b01fc0ace79c1b7d85c0facff34d35d [file] [log] [blame]
<?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-&gt;deref();
}
void Document::setTitle(Title* title)
{
if (title)
title-&gt;ref();
if (m_title)
m_title-&gt;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&lt;Title&gt; 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&lt;Title&gt; 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&lt;Title&gt; m_title;
}
void Document::setTitle(RefPtr&lt;Title&gt;&amp;&amp; title)
{
m_title = WTF::move(title);
}
<span class="comment">...</span>
RefPtr&lt;Title&gt; 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&lt;Title&gt; 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&lt;Node&gt; a = createSpecialNode();
RefPtr&lt;Node&gt; b = findNode();
Node* c = getOrdinaryNode();
<span class="comment">// the * operator</span>
*b = value;
<span class="comment">// the -&gt; operator</span>
a-&gt;clear();
b-&gt;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&lt;DerivedNode&gt; d = static_pointer_cast&lt;DerivedNode&gt;(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&lt;Node&gt; 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&lt;Node&gt; 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&lt;Node&gt; Node::create()
{
return adoptRef(*new Node);
}
Ref&lt;Node&gt; 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&lt;Node&gt; createSpecialNode()
{
Ref&lt;Node&gt; a = Node::create();
a-&gt;setCreated(true);
return a;
}
Ref&lt;Node&gt; 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&amp;&amp;</span>
or a <span class="class">RefPtr&amp;&amp;</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&amp;&amp; or Ref&amp;&amp;.</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&amp;&amp;, or RefPtr&amp;&amp;
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");
?>