<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">

<style type="text/css">

body { color: #000000; background-color: #FFFFFF; }
del { text-decoration: line-through; color: #8B0040; }
ins { text-decoration: underline; color: #005100; }

p.example { margin-left: 2em; }
pre.example { margin-left: 2em; }
div.example { margin-left: 2em; }

code.extract { background-color: #F5F6A2; }
pre.extract { margin-left: 2em; background-color: #F5F6A2;
  border: 1px solid #E1E28E; }

p.function { }
.attribute { margin-left: 2em; }
.attribute dt { float: left; font-style: italic;
  padding-right: 1ex; }
.attribute dd { margin-left: 0em; }

blockquote.std { color: #000000; background-color: #F1F1F1;
  border: 1px solid #D1D1D1;
  padding-left: 0.5em; padding-right: 0.5em; }
blockquote.stddel { text-decoration: line-through;
  color: #000000; background-color: #FFEBFF;
  border: 1px solid #ECD7EC;
  padding-left: 0.5empadding-right: 0.5em; ; }

blockquote.stdins { text-decoration: underline;
  color: #000000; background-color: #C8FFC8;
  border: 1px solid #B3EBB3; padding: 0.5em; }

table { border: 1px solid black; border-spacing: 0px;
  margin-left: auto; margin-right: auto; }
th { text-align: left; vertical-align: top;
  padding-left: 0.8em; border: none; }
td { text-align: left; vertical-align: top;
  padding-left: 0.8em; border: none; }

</style>

<title>shared_ptr::weak_type</title>
</head>
<body>

<b>Document number:</b> P0163R0 <br>
<b>Date:</b> 2015-10-23 <br>
<b>Project:</b> ISO JTC1/SC22/WG21, Programming Language C++ <br>
<b>Audience:</b> Library Evolution Working Group <br>
<b>Reply to:</b> Arthur O'Dwyer &lt;arthur.j.odwyer@gmail.com&gt; <br>

<h1>shared_ptr::weak_type</h1>

<p>
<a href="#Introduction">1. Introduction</a><br>
<a href="#Problem">2. Problem: Generic programming and <code>weak_ptr</code></a><br>
<a href="#One_more_example">3. One more motivating example</a></br>
<a href="#Solution">4. Solution</a><br>
<a href="#Rejected">5. Alternatives rejected at Kona</a><br>
<a href="#Proposed_wording">6. Proposed wording</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Proposed_wording_17">6a. Proposed wording for C++17 [util.smartptr.shared]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#util.smartptr.shared">6b. Proposed wording for Library Fundamentals V2 [memory.smartptr.shared]</a><br>
<a href="#References">7. References</a><br>
<a href="#Thanks">8. Thanks</a><br>
</p>


<h2><a name="Introduction">1. Introduction</a></h2>

<p>
This paper identifies a minor inconvenience in the design of <code>shared_ptr</code>,
in that it is impossible to create a <code>weak_ptr</code> from a <code>shared_ptr</code>
without explicitly spelling out the type of the <code>weak_ptr</code>, which impedes
generic programming. N4537 <a href="#N4537">[N4537]</a> proposed to solve this problem
by introducing the member function <code>shared_ptr<T>::unlock()</code>, but this idea
was rejected by LEWG at Kona. LEWG strongly supported the idea of providing a member
typedef <code>shared_ptr<T>::weak_type</code>, so that's what the present paper proposes,
for both C++17 and Library Fundamentals V2.
</p>

<h2><a name="Problem">2. Problem: Generic programming and <code>weak_ptr</code></a></h2>

<p>
Given an arbitrary <code>shared_ptr</code>, write code to "weaken" the object into
a <code>weak_ptr</code> with the same shared ownership and stored pointer.
</p>

<pre>
    template&lt;class ObjectType&gt;
    void register_observers(ObjectType&amp; obj)
    {
        auto sptr = obj.get_shared_ptr(); // for example, via shared_from_this
        auto wptr = weak_ptr&lt;ObjectType&gt;(sptr);
        sptr.reset(); // drop the strong reference as soon as possible
        register_observer_1(wptr);
        register_observer_2(wptr);
    }
</pre>

<p>
Unfortunately, this code is not perfectly generic: it will fail (or at least
do the wrong thing) in the case that <code>obj.get_shared_ptr()</code>
returns something other than <code>shared_ptr&lt;ObjectType&gt;</code>.
For example, it might return <code>shared_ptr&lt;BaseClassOfObjectType&gt;</code>.
Or, in an advanced scenario, we might want to be able to "drop in" a
replacement class <code>custom_shared_ptr</code> instead of the standard
<code>shared_ptr</code>, in which case we would also have to replace
<code>weak_ptr</code> in the above code with <code>custom_weak_ptr</code>.
</p>

<p>
Notice that at least two values of "custom_shared_ptr" exist in the wild:
<code>std::experimental::shared_ptr</code> in Library Fundamentals <a href="#N4077">[N4077]</a>,
and <code>boost::shared_ptr</code>. Neither of these implementations
currently provide <code>weak_type</code>. This paper proposes adding
<code>weak_type</code> to both C++17 and Library Fundamentals V2.
</p>

<p>
Notice that the <em>only</em> place in the code sample where an explicit
type is used, is in the line concerned with "weakening" <code>sptr</code>.
"Weakening" a <code>shared_ptr</code> into a <code>weak_ptr</code> is not
an operation that ought to force explicit types into otherwise generic code.
</p>

<h2><a name="One_more_example">3. One more motivating example</a></h2>
<p>
A real-world example of this pattern cropped up recently when Arthur attempted
to implement a "task-based programming" library with task cancellation, as
described in Sean Parent's "Better Code: Concurrency" <a href="#Parent">[Parent]</a>.
In this library, the <code>TaskControlBlock</code> is the central concept;
a <code>Future</code> is simply a thin wrapper around a
<code>std::shared_ptr&lt;TaskControlBlock&gt;</code>, and a
<code>CancellablePackagedTask</code> is a thin wrapper around a
<code>std::weak_ptr&lt;TaskControlBlock&gt;</code>.
When the last <code>Future</code> referring to a <code>TaskControlBlock</code>
is destroyed, the <code>TaskControlBlock</code> itself (if the task has not
yet begun to execute) may be destroyed. The implementation of
<code>EnqueueTask</code> in this system looks like this:
<pre>
    template&lt;typename T&gt;
    inline std::weak_ptr&lt;T&gt; Unlock(const std::shared_ptr&lt;T&gt;& sptr)
    {
        return std::weak_ptr&lt;T&gt;(sptr);
    }

    template&lt;typename Func&gt;
    auto EnqueueTask(Func&amp;&amp; func) -&gt; Future&lt;decltype(func())&gt;
    {
        using T = decltype(func());

        auto sptr = std::make_shared&lt;TaskControlBlock&lt;T&gt;&gt;();

        auto task = [
            func = std::forward&lt;Func&gt;(func),
            wptr = Unlock(sptr)
        ]() {
            Promise&lt;T&gt; px { wptr };
            px.set_value(func());
        };

        GlobalTaskPool.submit(task);

        Future&lt;T&gt; fx { std::move(sptr) };
        return fx;
    }
</pre>
Notice the use of the hand-coded free function <code>Unlock(sptr)</code>; that's
a workaround for the unwieldy expression <code>std::weak_ptr&lt;TaskControlBlock&lt;T&gt;&gt;(sptr)</code>.
</p>

<h2><a name="Solution">4. Solution</a></h2>

<p>
We propose adding one new typedef to the standard library.
<code>shared_ptr</code> gains a member typedef
<pre>
    using weak_type = weak_ptr<T>;
</pre>
This allows us to rewrite the "problem" code above in
generic style, naming no types explicitly, as:
</p>

<pre>
    template&lt;class ObjectType&gt;
    void register_observers(ObjectType&amp; obj) {
        auto sptr = obj.get_shared_ptr(); // for example, via shared_from_this
        auto wptr = typename decltype(sptr)::weak_type{sptr};
        sptr.reset(); // drop the strong reference as soon as possible
        register_observer_1(wptr);
        register_observer_2(wptr);
    }
</pre>

<p>and the other example becomes:</p>

<pre>
        auto task = [
            func = std::forward&lt;Func&gt;(func),
            wptr = typename decltype(sptr)::weak_type{sptr}
        ]() {
            Promise&lt;T&gt; px { wptr };
            px.set_value(func());
        };
</pre>

<p>
The author is not happy with the proposed style's verbosity, but at least this
does solve the generic-programming problem. Also, this proposal avoids introducing
any further asymmetry (as would be the case if we introduced a free function
<code>std::weaken</code> without <code>std::strengthen</code>).
</p>

<h2><a name="Rejected">5. Alternatives rejected at Kona</a></h2>

<p>
At Kona (October 2015), the following was proposed and/or straw-polled as N4537:
<a href="https://issues.isocpp.org/show_bug.cgi?id=103">[Issues]</a>

<pre>
Do we want <code>sptr.unlock()</code> by that name, as proposed in N4537?
(consensus was against)

Do we want that functionality at all, e.g. under the name <code>std::weaken(sptr)</code>?
SF F  N  A  SA
1  1  6  6  1

Should we provide <code>shared_ptr&lt;T&gt;::weak_type</code>?
SF F  N  A  SA
0  10 5  0  1
</pre>

Therefore, this paper proposes only the member typedef that garnered support.
</p>

<h2><a name="Proposed_wording">6. Proposed wording</a></h2>

<h3><a name="Proposed_wording_17">6a. Proposed wording for C++17</a></h3>

<p>
The wording in this section is relative to WG21 draft N4527 <a href="#N4527">[N4527]</a>,
that is, the draft of the C++17 standard.
</p>

<h3><a name="util.smartptr.shared">20.8.2.2 Class template shared_ptr [util.smartptr.shared]</a></h3>

<p>
Edit paragraph 1 as follows.
</p>

<blockquote class="std">
<p>
<code>
    template<class T> class shared_ptr {<br>
    public:<br>
    &nbsp; typedef T element_type;<br>
    &nbsp; <ins>typedef weak_ptr&lt;T&gt; weak_type;</ins><br>
<br>
    &nbsp; // 20.8.2.2.1, constructors:<br>
</code>
</blockquote>

<h3><a name="Proposed_wording_LF">6b. Proposed wording for Library Fundamentals V2</a></h3>

<p>
The wording in this section is relative to WG21 draft N4529 <a href="#N4529">[N4529]</a>,
that is, the draft of Library Fundamentals V2.
</p>

<h3><a name="memory.smartptr.shared">8.2.1 Class template shared_ptr [memory.smartptr.shared]</a></h3>

<p>
Edit paragraph 1 as follows.
</p>

<blockquote class="std">
<p>
<code>
    template<class T> class shared_ptr {<br>
    public:<br>
    &nbsp; typedef typename remove_extent_t&lt;T&gt; element_type;<br>
    &nbsp; <ins>typedef weak_ptr&lt;T&gt; weak_type;</ins><br>
    &nbsp; // 8.2.1.1, shared_ptr constructors<br>
</code>
</blockquote>

<h2><a name="References">7. References</a></h2>

<dl>

<dt><a name="Issues">[Issues]</a></dt>
<dd>
"Bug 103: Adding Symmetry Between shared_ptr and weak_ptr" (October 2015).<br>
<a href="https://issues.isocpp.org/show_bug.cgi?id=103">
https://issues.isocpp.org/show_bug.cgi?id=103</a>.
</dd>

<dt><a name="N4077">[N4077]</a></dt>
<dd>
Jonathan Wakely. "Experimental shared_ptr for Library Fundamentals TS" (June 2014).<br>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4077.html">
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4077.html</a>.
</dd>

<dt><a name="N4527">[N4527]</a></dt>
<dd>
"Working Draft, Standard for Programming Language C++" (May 2015).<br>
<a href="http://isocpp.org/files/papers/n4527.pdf">
http://isocpp.org/files/papers/n4527.pdf</a>.
</dd>

<dt><a name="N4529">[N4529]</a></dt>
<dd>
"Working Draft, C++ Extensions for Library Fundamentals, Version 2" (May 2015).<br>
<a href="http://isocpp.org/files/papers/n4529.pdf">
http://isocpp.org/files/papers/n4529.pdf</a>.
</dd>

<dt><a name="N4537">[N4537]</a></dt>
<dd>
Arthur O'Dwyer. "Adding Symmetry Between shared_ptr and weak_ptr" (May 2015).<br>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4537.html">
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4537.html</a>.
</dd>

<dt><a name="Parent">[Parent]</a></dt>
<dd>
"Better Code: Concurrency" (February 2015).<br>
<a href="https://github.com/sean-parent/sean-parent.github.io/wiki/Papers-and-Presentations">
https://github.com/sean-parent/sean-parent.github.io/wiki/Papers-and-Presentations</a>.
</dd>
</dl>

<h2><a name="Thanks">8. Thanks</a></h2>

<p>
Thanks to LEWG for feedback on N4537, and to Jonathan Wakely for feedback and for the
correct spelling of his surname.
</p>

</body>
</html>
