<html>

<head>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF8">

  <meta name="description" content="Proposal for C++ Standard">
  <meta name="keywords" content="C++,cplusplus,wg21">
  <meta name="author" content="Alisdair Meredith">

  <title>Revising atomic_shared_ptr for C++20</title>

  <style type="text/css">
    ins {background-color:#A0FFA0}
    del {background-color:#FFA0A0}
    p {text-align:justify}
    li {text-align:justify}
    blockquote.note
    {
      background-color:#E0E0E0;
      padding-left: 15px;
      padding-right: 15px;
      padding-top: 1px;
      padding-bottom: 1px;
    }
    blockquote.recommend
    {
      background-color:#ffffb0;
      padding-left: 10px;
      padding-right: 10px;
      padding-top: 1px;
      padding-bottom: 1px;
    }
  </style>
</head>

<body>
<table>
<tr>
  <td align="left">Doc. no.</td>
  <td align="left">P0718R0</td>
</tr>
<tr>
  <td align="left">Date:</td>
  <td align="left">2017-06-19</td>
</tr>
<tr>
  <td align="left">Project:</td>
  <td align="left">Programming Language C++</td>
</tr>
<tr>
  <td align="left">Audience:</td>
  <td align="left">SG1</td>
</tr>
<tr>
  <td align="left"></td>
  <td align="left">Library Evolution Working Group</td>
</tr>
<tr>
  <td align="left"></td>
  <td align="left">Library Working Group</td>
</tr>
<tr>
  <td align="left">Reply to:</td>
  <td align="left">Alisdair Meredith &lt;<a href="mailto:ameredith1@bloomberg.net">ameredith1@bloomberg.net</a>&gt;</td>
</tr>
</table>

<h1>Revising <tt>atomic_shared_ptr</tt> for C++20</h1>

<h2>Table of Contents</h2>
<ol start="0">
<li><a href="#rev.hist">Revision History</a></li>
  <ul>
  <li><a href="#rev.0">Revision 0</a></li>
  </ul>
<li><a href="#1.0">Introduction</a></li>
<li><a href="#2.0">Stating the problem</a></li>
  <ul>
  <li><a href="#2.1">Consistency of propagation traits</a></li>
  </ul>
<li><a href="#3.0">Propose Solution</a></li>
  <ul>
  <li><a href="#3.1">Move Atomic Smart Pointers to the <tt>&lt;memory&gt;</tt> Header</a></li>
  <li><a href="#3.2">Restore the <tt>atomic&lt;shared_ptr&lt;T&gt;&gt;</tt> Partial Specialization</a></li>
  <li><a href="#3.3">Deprecate the C++11 Atomic Interface for <tt>shared_ptr</tt></a></li>
  <li><a href="#3.4">Fix Up Minor Wording Nits</a></li>
  </ul>
<li><a href="#4.0">Other Directions</a></li>
<li><a href="#5.0">Formal Wording</a></li>
<li><a href="#6.0">Acknowledgements</a></li>
<li><a href="#7.0">References</a></li>
</ol>


<h2><a name="rev.hist">Revision History</a></h2>

<h3><a name="rev.0">Revision 0</a></h3>
<p>
Original version of the paper for the 2017 pre-Toronto mailing.
</p>

<h2><a name="1.0">1 Introduction</a></h2>
<p>
The Concurrency TS introduced two atomic smart pointer classes,
<tt>atomic_shared_ptr</tt> and <tt>atomic_weak_ptr</tt>, as a superior
alternative to the atomic access API for <tt>shared_ptr</tt> in the C++
standard.  This paper highlights several issues with that specification that
should be resolved before merging its contents into a future C++ standard.
</p>


<h2><a name="2.0">2 Stating the problem</a></h2>
<p>
The C++ standard provides an API to access and manipulate specific
<tt>shared_ptr</tt> objects atomically, i.e., without introducing data races
when the same object is manipulated from multiple threads without further
synchronization.  This API is fragile and error-prone, as <tt>shared_ptr</tt>
objects manipulated through this API are indistinguishable from other
<tt>shared_ptr</tt> objects, yet subject to the restriction that they may be
manipulated/accessed <i>only</i> through this API.  In particular, you cannot
dereference such a <tt>shared_ptr</tt> without first loading it into another
<tt>shared_ptr</tt> object, and then dereferencing through the second object.
</p>

<p>
The Concurrency TS addresses this fragility with a class template to implicitly
wrap a <tt>shared_ptr</tt> and guarantee to access it only through the atomic
access API.  It provides a similar wrapper for <tt>weak_ptr</tt>, although the
standard does not provide a corresponding atomic access API for
<tt>weak_ptr</tt>s.
</p>

<p>
The atomic wrapper classes are placed in the <tt>&lt;atomic&gt;</tt> header,
which is part of the free-standing library, while the smart pointer classes it
wraps, and the corresponding atomic access API, are located in the
<tt>&lt;memory&gt;</tt> header, which is not free-standing.
</p>

<p>
The atomic wrapper classes are designed to look like the named type aliases for
specific instantiations of the <tt>atomic</tt> template, but are distinct class
templates in their own right.  While this risks confusing users, the
specification is in terms of the primary <tt>atomic</tt> template, which may
lead to subtle wording issues where the name of the template is involved.  It
also means that the smart pointer wrapper classes are not compatible with other
functions in the <tt>&lt;atomic&gt;</tt> header that act on the <tt>atomic</tt>
template, such as (C compatible) free-function APIs that correspond to member
functions.
</p>


<h2><a name="3.0">3 Propose Solution</a></h2>

<h3><a name="3.1">3.1 Move Atomic Smart Pointers to the <tt>&lt;memory&gt;</tt> Header</a></h3>
<p>
The whole feature of wrapping smart pointers in an atomic type relies on
contents of the <tt>&lt;memory&gt;</tt> header, including (as currently
specified) the atomic access API to be invoked.  Rather than create a
dependency between the free-standing <tt>&lt;atomic&gt;</tt> header and the
hosted <tt>&lt;memory&gt;</tt> header, we should simply move the whole
smart-pointer specification into the <tt>&lt;memory&gt;</tt> header.
</p>

<h3><a name="3.2">3.2 Restore the <tt>atomic&lt;shared_ptr&lt;T&gt;&gt;</tt> Partial Specialization</a></h3>
<p>
The smart pointer wrapper types in the Concurrency TS are deliberately named to
look like a named alias of the <tt>atomic</tt> template.  However, as they are
not in fact such an alias, they are not usable in many APIs from the
<tt>&lt;atomic&gt;</tt> header that are truly specified in terms of the
<tt>atomic</tt> template.  This is a recipe for confusion.
</p>
<p>
Rather than rename the atomic wrapper templates, this paper suggests revisiting
the reason we chose to make such class templates in the first place, rather
than more naturally providing partial specializations for the <tt>atomic</tt>
class template.  In particular, it appears that the reason we deferred on the
original proposal
(<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4058.pdf">N4058</a>)
specializing the <tt>atomic</tt> template was concern about the constraint that
<tt>T</tt> must be trivially copyable for <tt>atomic&lt;T&gt;</tt>.  However,
this is fundamentally a constraint on what the library is committing to support
when provided an otherwise unknown type by a user, rather than a constraint on
what the library itself can support with more knowledge of a specific type.  In
particular, it is not clear how to specify constraints for the primary template
to support non-trivial types, while it is clear how to specify known special
cases such as smart pointers.  Forcing the library to use a different interface
will produce a substandard user experience, for no apparent gain.
</p>
<p>
This paper proposes restoring the original proposal's idea for
<tt>atomic&lt;</tt><i>smart-pointer</i><tt>&gt;</tt> and supplying named alias
templates, as per the atomic integral classes.  We note in passing that there
is no similar alias-template for:
<blockquote><pre>
template &lt;typename T&gt;
using atomic_pointer = atomic&lt;T*&gt;;
</pre></blockquote>
This would probably be a sought-for addition once the atomic wrappers have
their specific names.  However, it is not proposed in the initial draft of this
paper.
</p>

<h3><a name="3.3">3.3 Deprecate the C++11 Atomic Interface for <tt>shared_ptr</tt></a></h3>
<p>
The atomic access API in clause 23 is fragile and easy to misuse.  It overloads
the atomic API for atomic objects in the <tt>&lt;atomic&gt;</tt> header with
identical names and signatures for manipulating non-atomic objects.  There is
no other precedent for this (existing) API.  It should be deprecated in favor
of the new atomic smart pointer support.  However, the atomic types in the
Concurrency TS are specified in terms of that same API.
</p>
<p>
However, looking at the specification for the API in C++17, we see that it
should be simple to rewrite the specification for the atomic pointer without
reference to this API.
</p>
<p>
First, consumers of this API can access the smart pointer object only through
this API.  This would potentially be giving up an interoperability feature, but
there is no public access to the wrapped smart pointer, so no other code can
interact (directly) with our wrapped objects using this API.  No generality is
given up.
</p>
<p>
Secondly, each API documents a requirement that it is not called with null
pointers, and this is not a useful precondition when replaced with a
member-function based API, which can guarantee such preconditions are always
satisfied without documenting them.
</p>
<p>
The important reason these functions are documented separately to those in
clause 32 is to highlight that smart pointer objects have the same value when
both the held pointer values are the same, and the shared control blocks are
the same.  This is not the same as the simple equality operator on these types,
which compares only the held pointer value, and in fact, <tt>weak_ptr</tt> does
not even offer an <tt>operator==</tt> to test.  Similarly, the exchange
semantics are specified as-if calling the member <tt>swap</tt> function.
</p>
<p>
Finally, there is no such atomic access API for <tt>weak_ptr</tt> at all, and
it is simpler to directly specify the operations of the wrapper template than
to provide a second fragile API to use by reference.
</p>

<h3><a name="3.4">3.4 Fix Up Minor Wording Nits</a></h3>
<p>
There are a small number of minor nits in the specification that should also be
cleaned up.
</p>
<p>
The Concurrency TS seems to assume that it is sufficient to state that a smart
pointer is empty, assuming that means it is also null.  However, through the
aliasing constructor, <tt>shared_ptr</tt> objects can still hold valid pointers
while empty, i.e., when not owning an object.
</p>

<p>
The Concurrency TS also assumes there is a &quot;valid-but-unspecified&quot;
moved-from state for shared and weak pointers, but the specification for these
types is precise in all cases, and objects are left empty after a successful
move operation.  It further gives the guarantee that lvalue references are not
accessed again after the atomic step, but for no obvious reason does not give
the same guarantee in the case of rvalue references.  Given the state must be
reset to empty (by shared/weak-pointer semantics) as part of the atomic update,
there is no reason to not give the same guarantee for all reference types.
</p>

<p>
The Concurrency TS specification is missing the <tt>value_type</tt> type alias,
and the static constant member <tt>is_always_lock_free</tt>.
</p>

<p>
The Concurrency TS types do not return a value from <tt>operator=</tt>, unlike
the specification for <tt>atomic</tt> that they are defined in terms of.  It
would be very easy to non-atomically return the supplied argument after atomically
storing the value, matching the primary <tt>atomic</tt> template, but the author
prefers to keep the specification as close to the TS as possible, despite his own
preference for preserving the primary template interfaces as much as possible.
</p>

<h2><a name="4.0">4 Other Directions</a></h2>
<p>
The primary <tt>atomic</tt> template has a <tt>volatile</tt>-qualified overload
for every member function.  This allows for the idiom that objects that may be
modified outside the current thread are maked as <tt>volatile</tt> to raise
their visibility.  The original proposal, as adopted by the TS and repeated in
this paper, is to not support that for atomic smart pointers.  Without casting
prejudice on the idiom, non-atomic smart pointers do not have the overloaded
constructors taking <tt>volatile</tt> references, so the idiom is not supported
by the underlying types.  This is one way that fundamentaly types typically
differ from user-defined types, and the clause 32 specializations of
<tt>atomic</tt> are dealing only with fundamental types that transparently
handle the <tt>volatile</tt> qualifier.
</p>

<p>
The TS specification splits compare_exchange methods taking a non-atomic
argument by value into two overloads for lvalues and rvalues, allowing for
the most efficient argument passing for smart pointers.  It does not do the
same for other members that would simlarly benefit, such as the by-value
constructor and the assignment operator.  This paper conservatively does not
propose such a split either, while observing the original specification is
in terms of a free-function API that is similarly specified to take
<tt>shared_ptr</tt> objects by value, so there would be no benefit to making
that split in the original specification.  While the split seems beneficial
once freed from that specification, the author has no implementation
experience to confirm that it is would be implementable or valuable.
</p>

<p>
As noted above, the partial specializations for atomic smart pointers could
better respect the primary template interface, such as by (non-atomically)
returning a value from the assignment operator.
</p>


<h2><a name="5.0">5 Formal Wording</a></h2>
<p>
Make the following changes to the specified working paper.  Note that as the
proposed wording is not yet present in the C++ Working Paper, and there are no
outstanding issues filed against these clauses of the Concurrency TS, we do not
feel bound by the existing stable names for the clauses, and so propose new
stable names appropriate for landing in the current C++ Working Paper.
</p>

<p>
Update the synopsis for the <tt>&lt;memory&gt;</tt> header as follows.  Note
that the addition of <tt>reinterpret_pointer_cast</tt> is an editorial
drive-by, the function is already part of C++17.
</p>

<blockquote>
<h4>23.10.2 Header <tt>&lt;memory&gt;</tt> synopsis [memory.syn]</h4>
<ol>
<li>
The header <tt>&lt;memory&gt;</tt> defines several types and function templates
that describe properties of pointers and pointer-like types, manage memory for
containers and other template types, destroy objects, and construct multiple
objects in uninitialized memory buffers (23.10.3–23.10.10). The header also
defines the templates <tt>unique_ptr</tt>, <tt>shared_ptr</tt>, <tt>weak_ptr</tt>,
and various function templates that operate on objects of these types (23.11).
</li>
</ol>
<blockquote><pre>
<ins>#include &lt;atomic&gt;</ins>

namespace std {
// ...

// 23.11.2.2, class template shared_ptr
template&lt;class T&gt; class shared_ptr;

// 23.11.2.2.6, shared_ptr creation
template&lt;class T, class... Args&gt;
  shared_ptr&lt;T&gt; make_shared(Args&amp;&amp;... args);
template&lt;class T, class A, class... Args&gt;
  shared_ptr&lt;T&gt; allocate_shared(const A&amp; a, Args&amp;&amp;... args);

// 23.11.2.2.7, shared_ptr comparisons
template&lt;class T, class U&gt;
  bool operator==(const shared_ptr&lt;T&gt;&amp; a, const shared_ptr&lt;U&gt;&amp; b) noexcept;
template&lt;class T, class U&gt;
  bool operator!=(const shared_ptr&lt;T&gt;&amp; a, const shared_ptr&lt;U&gt;&amp; b) noexcept;
template&lt;class T, class U&gt;
  bool operator&lt;(const shared_ptr&lt;T&gt;&amp; a, const shared_ptr&lt;U&gt;&amp; b) noexcept;
template&lt;class T, class U&gt;
  bool operator&gt;(const shared_ptr&lt;T&gt;&amp; a, const shared_ptr&lt;U&gt;&amp; b) noexcept;
template&lt;class T, class U&gt;
  bool operator&lt;=(const shared_ptr&lt;T&gt;&amp; a, const shared_ptr&lt;U&gt;&amp; b) noexcept;
template&lt;class T, class U&gt;
  bool operator&gt;=(const shared_ptr&lt;T&gt;&amp; a, const shared_ptr&lt;U&gt;&amp; b) noexcept;

template &lt;class T&gt;
  bool operator==(const shared_ptr&lt;T&gt;&amp; x, nullptr_t) noexcept;
template &lt;class T&gt;
  bool operator==(nullptr_t, const shared_ptr&lt;T&gt;&amp; y) noexcept;
template &lt;class T&gt;
  bool operator!=(const shared_ptr&lt;T&gt;&amp; x, nullptr_t) noexcept;
template &lt;class T&gt;
  bool operator!=(nullptr_t, const shared_ptr&lt;T&gt;&amp; y) noexcept;
template &lt;class T&gt;
  bool operator&lt;(const shared_ptr&lt;T&gt;&amp; x, nullptr_t) noexcept;
template &lt;class T&gt;
  bool operator&lt;(nullptr_t, const shared_ptr&lt;T&gt;&amp; y) noexcept;
template &lt;class T&gt;
  bool operator&lt;=(const shared_ptr&lt;T&gt;&amp; x, nullptr_t) noexcept;
template &lt;class T&gt;
  bool operator&lt;=(nullptr_t, const shared_ptr&lt;T&gt;&amp; y) noexcept;
template &lt;class T&gt;
  bool operator&gt;(const shared_ptr&lt;T&gt;&amp; x, nullptr_t) noexcept;
template &lt;class T&gt;
  bool operator&gt;(nullptr_t, const shared_ptr&lt;T&gt;&amp; y) noexcept;
template &lt;class T&gt;
  bool operator&gt;=(const shared_ptr&lt;T&gt;&amp; x, nullptr_t) noexcept;
template &lt;class T&gt;
  bool operator&gt;=(nullptr_t, const shared_ptr&lt;T&gt;&amp; y) noexcept;

// 23.11.2.2.8, shared_ptr specialized algorithms
template &lt;class T&gt;
      void swap(shared_ptr&lt;T&gt;&amp; a, shared_ptr&lt;T&gt;&amp; b) noexcept;

// 23.11.2.2.9, shared_ptr casts
template&lt;class T, class U&gt;
  shared_ptr&lt;T&gt; static_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
template&lt;class T, class U&gt;
  shared_ptr&lt;T&gt; dynamic_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
template&lt;class T, class U&gt;
  shared_ptr&lt;T&gt; const_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
<ins>template&lt;class T, class U&gt;</ins>
  <ins>shared_ptr&lt;T&gt; reinterpret_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;</ins>

// 23.11.2.2.10, shared_ptr get_deleter
template&lt;class D, class T&gt;
  D* get_deleter(const shared_ptr&lt;T&gt;&amp; p) noexcept;

// 23.11.2.2.11, shared_ptr I/O
template&lt;class E, class T, class Y&gt;
  basic_ostream<E, T>&amp; operator&lt;&lt; (basic_ostream&lt;E, T&gt;&amp; os, const shared_ptr&lt;Y&gt;&amp; p);

// 23.11.2.3, class template weak_ptr
template&lt;class T&gt; class weak_ptr;

// 23.11.2.3.6, weak_ptr specialized algorithms
template&lt;class T&gt; void swap(weak_ptr&lt;T&gt;&amp; a, weak_ptr&lt;T&gt;&amp; b) noexcept;

// 23.11.2.4, class template owner_less
template&lt;class T = void&gt; struct owner_less;

// 23.11.2.5, class template enable_shared_from_this
template&lt;class T&gt; class enable_shared_from_this;

<del>// 23.11.2.6, shared_ptr atomic access</del>
<del>template &lt;class T&gt;</del>
  <del>bool atomic_is_lock_free(const shared_ptr&lt;T&gt;* p);</del>

<del>template &lt;class T&gt;</del>
  <del>shared_ptr&lt;T&gt; atomic_load(const shared_ptr&lt;T&gt;* p);</del>
<del>template &lt;class T&gt;</del>
  <del>shared_ptr&lt;T&gt; atomic_load_explicit(const shared_ptr&lt;T&gt;* p, memory_order mo);</del>

<del>template &lt;class T&gt;</del>
  <del>void atomic_store(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r);</del>
<del>template &lt;class T&gt;</del>
  <del>void atomic_store_explicit(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r, memory_order mo);</del>

<del>template &lt;class T&gt;</del>
  <del>shared_ptr&lt;T&gt; atomic_exchange(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r);</del>
<del>template &lt;class T&gt;</del>
  <del>shared_ptr&lt;T&gt; atomic_exchange_explicit(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r, memory_order mo);</del>

<del>template &lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_weak(</del>
    <del>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w);</del>
<del>template &lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_strong(</del>
    <del>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w);</del>
<del>template &lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_weak_explicit(</del>
    <del>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w,</del>
    <del>memory_order success, memory_order failure);</del>
<del>template &lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_strong_explicit(</del>
    <del>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w,</del>
    <del>memory_order success, memory_order failure);</del>

// 23.11.2.7, hash support
template &lt;class T&gt; struct hash;
template &lt;class T, class D&gt; struct hash&lt;unique_ptr&lt;T, D&gt;&gt;;
template &lt;class T&gt; struct hash&lt;shared_ptr&lt;T&gt;&gt;;

<ins>// 23.11.3, atomic smart pointers</ins>
<ins>template template &lt;class T&gt; struct atomic&lt;shared_ptr&lt;T&gt;&gt;;</ins>
<ins>template template &lt;class T&gt; struct atomic&lt;weak_ptr&lt;T&gt;&gt;;</ins>

<ins>template template &lt;class T&gt; using atomic_shared_ptr = atomic&lt;shared_ptr&lt;T&gt;&gt;;</ins>
<ins>template template &lt;class T&gt; using atomic_weak_ptr   = atomic&lt;weak_ptr&lt;T&gt;&gt;;</ins>

// ...
}
</pre></blockquote>
</blockquote>

<p>
Add a new clause 23.11.3 to specify atomic smart pointers:
</p>

<blockquote>
<h4><ins>23.11.3 <tt>atomic</tt> specializations for smart pointers [util.smartptr.atomic]</ins></h4>

<ol>
<li><ins>
The library shall provide partial specializations of the <tt>atomic</tt> template
shared-ownership smart pointers.  The behavior of all operations is as specified
in §32.6 [atomics.types.generic], unless specified otherwise.   The template
parameter <tt>T</tt> of these partial specializations may be an incomplete type.
</li></ins>

<li><ins>
All changes to an <tt>atomic</tt> smart pointer in this subclause, and all associated
<tt>use_count</tt> increments, are guaranteed to be performed atomically.
Associated <tt>use_count</tt> decrements shall be sequenced after the atomic
operation, but are not required to be part of it. Any associated deletion and
deallocation are sequenced after the atomic update step and shall not be part
of the atomic operation. [ <i>Note:</i> If the atomic operation uses locks,
locks acquired by the implementation shall be held when any <tt>use_count</tt>
adjustments are performed, and shall not be held when any destruction or
deallocation resulting from this is performed. <i>&mdash; end note</i> ]
</li></ins>

<li><ins>
For the purpose of compare_exchange operations, two <tt>weak_ptr</tt> objects are
equivalent if they are both empty, or if they shared ownership and store the same
pointer value.
</li></ins>


</ol>

<h4><ins>23.11.3.1 <tt>atomic</tt> specialization for <tt>shared_ptr</tt> [util.smartptr.atomic.shared]</ins></h4>

<blockquote><pre>
<ins>namespace std {</ins>
<ins>template <class T> struct atomic&lt;shared_ptr&lt;T&gt;&gt; {</ins>
    <ins>using value_type = shared_ptr&lt;T&gt;;</ins>
    <ins>static constexpr bool is_always_lock_free = <i>implementation-defined</i>;</ins>

    <ins>bool is_lock_free() const noexcept;</ins>
    <ins>void store(shared_ptr&lt;T&gt; desired, memory_order order = memory_order_seq_cst) noexcept;</ins>
    <ins>shared_ptr<T> load(memory_order order = memory_order_seq_cst) const noexcept;</ins>
    <ins>operator shared_ptr&lt;T&gt;() const noexcept;</ins>

    <ins>shared_ptr&lt;T&gt; exchange(shared_ptr&lt;T&gt; desired, memory_order = memory_order_seq_cst) noexcept;</ins>

    <ins>bool compare_exchange_weak(shared_ptr&lt;T&gt;&amp; expected, const shared_ptr&lt;T&gt;&amp; desired,</ins>
          <ins>memory_order success, memory_order failure) noexcept;</ins>
    <ins>bool compare_exchange_weak(shared_ptr&lt;T&gt;&amp; expected, shared_ptr&lt;T&gt;&amp;&amp; desired,</ins>
          <ins>memory_order success, memory_order failure) noexcept;</ins>
    <ins>bool compare_exchange_strong(shared_ptr&lt;T&gt;&amp; expected, const shared_ptr&lt;T&gt;&amp; desired,</ins>
          <ins>memory_order success, memory_order failure) noexcept;</ins>
    <ins>bool compare_exchange_strong(shared_ptr&lt;T&gt;&amp; expected, shared_ptr&lt;T&gt;&amp;&amp; desired,</ins>
          <ins>memory_order success, memory_order failure) noexcept;</ins>

    <ins>bool compare_exchange_weak(shared_ptr&lt;T&gt;&amp; expected, const shared_ptr&lt;T&gt;&amp; desired,</ins>
          <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
    <ins>bool compare_exchange_weak(shared_ptr&lt;T&gt;&amp; expected, shared_ptr&lt;T&gt;&amp;&amp; desired,</ins>
          <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
    <ins>bool compare_exchange_strong(shared_ptr&lt;T&gt;&amp; expected, const shared_ptr&lt;T&gt;&amp; desired,</ins>
          <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
    <ins>bool compare_exchange_strong(shared_ptr&lt;T&gt;&amp; expected, shared_ptr&lt;T&gt;&amp;&amp; desired,</ins>
          <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>

    <ins>constexpr atomic() noexcept = default;</ins>
    <ins>atomic(shared_ptr&lt;T&gt; desired) noexcept;</ins>
    <ins>atomic(const atomic&amp;) = delete;</ins>
    <ins>void operator=(const atomic&amp;) = delete;</ins>
    <ins>void operator=(shared_ptr&lt;T&gt; desired) noexcept;</ins>

  <ins>private:</ins>
    <ins>shared_ptr&lt;T&gt; p;  // exposition only</ins>
<ins>};
<ins>}
</pre></blockquote>

<ol>
<blockquote><pre>
<ins>constexpr atomic() noexcept = default;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Initializes the <tt>atomic</tt> object to an empty null value.
</ins></li>


<blockquote><pre>
<ins>atomic(shared_ptr&lt;T&gt; desired) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Initializes the object with the value <tt>desired</tt>.
Initialization is not an atomic operation (4.7). [ <i>Note:</i> It is possible
to have an access to an atomic object <tt>A</tt> race with its construction,
for example by communicating the address of the just-constructed object
<tt>A</tt> to another thread via <tt>memory_order_relaxed</tt> operations on a
suitable atomic pointer variable, and then immediately accessing <tt>A</tt> in
the receiving thread. This results in undefined behavior. <i>&mdash; end note</i> ]
</ins></li>


<blockquote><pre>
<ins>void store(shared_ptr&lt;T&gt; desired, memory_order order = memory_order_seq_cst) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Requires:</i> The order argument shall not be <tt>memory_order_consume</tt>,
<tt>memory_order_acquire</tt>, nor <tt>memory_order_acq_rel</tt>.
</ins></li>

<li><ins>
<i>Effects:</i> Atomically replaces the value pointed to by <tt>this</tt> with
the value of <tt>desired</tt> as if by <tt>p-&gt;swap(desired)</tt>. Memory is
affected according to the value of
<tt>order</tt>.
</ins></li>


<blockquote><pre>
<ins>void operator=(shared_ptr&lt;T&gt; desired) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Equivalent to: <tt>store(desired)</tt>.
</ins></li>


<blockquote><pre>
<ins>shared_ptr<T> load(memory_order order = memory_order_seq_cst) const noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Requires:</i> <tt>order</tt> shall not be <tt>memory_order_release</tt> or
<tt>memory_order_acq_rel</tt>.
</ins></li>

<li><ins>
<i>Effects:</i> Memory is affected according to the value of <tt>order</tt>.
</ins></li>

<li><ins>
<i>Returns:</i> Atomically returns <tt>*p</tt>.
</ins></li>


<blockquote><pre>
<ins>operator shared_ptr&lt;T&gt;() const noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Equivalent to: <tt>return load();</tt>
</ins></li>


<blockquote><pre>
<ins>shared_ptr&lt;T&gt; exchange(shared_ptr&lt;T&gt; desired, memory_order = memory_order_seq_cst) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Atomically replaces <tt>p</tt> with <tt>desired</tt> as if by
<tt>p-&gt;swap(desired)</tt>. Memory is affected according to the value of
<tt>order</tt>.  This is an atomic read-modify-write operation (4.7.1
[intro.races]).
</ins></li>

<li><ins>
<i>Returns:</i> Atomically returns the value of <tt>*p</tt> immediately before the effects.
</ins></li>


<blockquote><pre>
<ins>bool compare_exchange_weak(shared_ptr&lt;T&gt;&amp; expected, const shared_ptr&lt;T&gt;&amp; desired,</ins>
      <ins>memory_order success, memory_order failure) noexcept;</ins>
<ins>bool compare_exchange_weak(shared_ptr&lt;T&gt;&amp; expected, shared_ptr&lt;T&gt;&amp;&amp; desired,</ins>
      <ins>memory_order success, memory_order failure) noexcept;</ins>
<ins>bool compare_exchange_strong(shared_ptr&lt;T&gt;&amp; expected, const shared_ptr&lt;T&gt;&amp; desired,</ins>
      <ins>memory_order success, memory_order failure) noexcept;</ins>
<ins>bool compare_exchange_strong(shared_ptr&lt;T&gt;&amp; expected, shared_ptr&lt;T&gt;&amp;&amp; desired,</ins>
      <ins>memory_order success, memory_order failure) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Requires:</i> <tt>failure</tt> shall not be <tt>memory_order_release</tt>
nor <tt>memory_order_acq_rel</tt>.
</ins></li>

<li><ins>
<i>Effects:</i> If <tt>p</tt> is equivalent to <tt>expected</tt>, assigns
<tt>desired</tt> to <tt>p</tt> and has synchronization semantics corresponding
to the value of <tt>success</tt>, otherwise assigns <tt>p</tt> to
<tt>expected</tt> and has synchronization semantics corresponding to the value
of <tt>failure</tt>.
</ins></li>

<li><ins>
<i>Returns:</i> <tt>true</tt> if <tt>p</tt> was equivalent to <tt>expected</tt>,
<tt>false</tt> otherwise.
</ins></li>

<li><ins>
<i>Remarks:</i> Two <tt>shared_ptr</tt> objects are equivalent if they store
the same pointer value and either share ownership, or both are empty.  The weak
form may fail spuriously. See 32.6.1.
</ins></li>

<li><ins>
If the operation returns <tt>true</tt>, <tt>expected</tt> is not accessed after
the atomic update and the operation is an atomic read-modify-write operation
(4.7) on the memory pointed to by this. Otherwise, the operation is an atomic
load operation on that memory, and <tt>expected</tt> is updated with the
existing value read from the <tt>atomic</tt> object in the attempted atomic
update.  The <tt>use_count</tt> update corresponding to the write to
<tt>expected</tt> is part of the atomic operation.  The write to
<tt>expected</tt> itself is not required to be part of the atomic operation.
<li><ins>

<li><ins>
If the <tt>desired</tt> value is passed by rvalue reference and the operation
returns <tt>true</tt>, then <tt>desired</tt> is empty after the atomic update
step.
</li></ins>



<blockquote><pre>
<ins>bool compare_exchange_weak(shared_ptr&lt;T&gt;&amp; expected, const shared_ptr&lt;T&gt;&amp; desired,</ins>
      <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Equivalent to: <tt>return compare_exchange_weak(expected, desired, order, fail_order);</tt>
where <tt>fail_order</tt> is the same as <tt>order</tt> except that a value of
<tt>memory_order_acq_rel</tt> shall be replaced by the value
<tt>memory_order_acquire</tt> and a value of <tt>memory_order_release</tt>
shall be replaced by the value <tt>memory_order_relaxed</tt>.
</ins></li>

<blockquote><pre>
<ins>bool compare_exchange_weak(shared_ptr&lt;T&gt;&amp; expected, shared_ptr&lt;T&gt;&amp;&amp; desired,</ins>
      <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Equivalent to: <tt>return compare_exchange_weak(expected, std::move(desired), order, fail_order);</tt>
where <tt>fail_order</tt> is the same as <tt>order</tt> except that a value of
<tt>memory_order_acq_rel</tt> shall be replaced by the value
<tt>memory_order_acquire</tt> and a value of <tt>memory_order_release</tt>
shall be replaced by the value <tt>memory_order_relaxed</tt>.
</ins></li>

<blockquote><pre>
<ins>bool compare_exchange_strong(shared_ptr&lt;T&gt;&amp; expected, const shared_ptr&lt;T&gt;&amp; desired,</ins>
      <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Equivalent to: <tt>return compare_exchange_strong(expected, desired, order, fail_order);</tt>
where <tt>fail_order</tt> is the same as <tt>order</tt> except that a value of
<tt>memory_order_acq_rel</tt> shall be replaced by the value
<tt>memory_order_acquire</tt> and a value of <tt>memory_order_release</tt>
shall be replaced by the value <tt>memory_order_relaxed</tt>.
</ins></li>

<blockquote><pre>
<ins>bool compare_exchange_strong(shared_ptr&lt;T&gt;&amp; expected, shared_ptr&lt;T&gt;&amp;&amp; desired,</ins>
      <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Equivalent to: <tt>return compare_exchange_strong(expected, std::move(desired), order, fail_order);</tt>
where <tt>fail_order</tt> is the same as <tt>order</tt> except that a value of
<tt>memory_order_acq_rel</tt> shall be replaced by the value
<tt>memory_order_acquire</tt> and a value of <tt>memory_order_release</tt>
shall be replaced by the value <tt>memory_order_relaxed</tt>.
</ins></li>


</ol>

<h4><ins>23.11.3.2 <tt>atomic</tt> specialization for <tt>weak_ptr</tt> [util.smartptr.atomic.weak]</ins></h4>

<blockquote><pre>
<ins>namespace std {</ins>
<ins>template <class T> struct atomic&lt;weak_ptr&lt;T&gt;&gt; {</ins>
    <ins>using value_type = weak_ptr&lt;T&gt;;</ins>
    <ins>static constexpr bool is_always_lock_free = <i>implementation-defined</i>;</ins>

    <ins>bool is_lock_free() const noexcept;</ins>
    <ins>void store(weak_ptr&lt;T&gt; desired, memory_order order = memory_order_seq_cst) noexcept;</ins>
    <ins>weak_ptr<T> load(memory_order order = memory_order_seq_cst) const noexcept;</ins>
    <ins>operator weak_ptr&lt;T&gt;() const noexcept;</ins>

    <ins>weak_ptr&lt;T&gt; exchange(weak_ptr&lt;T&gt; desired, memory_order = memory_order_seq_cst) noexcept;</ins>

    <ins>bool compare_exchange_weak(weak_ptr&lt;T&gt;&amp; expected, const weak_ptr&lt;T&gt;&amp; desired,</ins>
          <ins>memory_order success, memory_order failure) noexcept;</ins>
    <ins>bool compare_exchange_weak(weak_ptr&lt;T&gt;&amp; expected, weak_ptr&lt;T&gt;&amp;&amp; desired,</ins>
          <ins>memory_order success, memory_order failure) noexcept;</ins>
    <ins>bool compare_exchange_strong(weak_ptr&lt;T&gt;&amp; expected, const weak_ptr&lt;T&gt;&amp; desired,</ins>
          <ins>memory_order success, memory_order failure) noexcept;</ins>
    <ins>bool compare_exchange_strong(weak_ptr&lt;T&gt;&amp; expected, weak_ptr&lt;T&gt;&amp;&amp; desired,</ins>
          <ins>memory_order success, memory_order failure) noexcept;</ins>

    <ins>bool compare_exchange_weak(weak_ptr&lt;T&gt;&amp; expected, const weak_ptr&lt;T&gt;&amp; desired,</ins>
          <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
    <ins>bool compare_exchange_weak(weak_ptr&lt;T&gt;&amp; expected, weak_ptr&lt;T&gt;&amp;&amp; desired,</ins>
          <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
    <ins>bool compare_exchange_strong(weak_ptr&lt;T&gt;&amp; expected, const weak_ptr&lt;T&gt;&amp; desired,</ins>
          <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
    <ins>bool compare_exchange_strong(weak_ptr&lt;T&gt;&amp; expected, weak_ptr&lt;T&gt;&amp;&amp; desired,</ins>
          <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>

    <ins>constexpr atomic() noexcept = default;</ins>
    <ins>atomic(weak_ptr&lt;T&gt; desired) noexcept;</ins>
    <ins>atomic(const atomic&amp;) = delete;</ins>
    <ins>void operator=(const atomic&amp;) = delete;</ins>
    <ins>void operator=(weak_ptr&lt;T&gt; desired) noexcept;</ins>
<ins>};
<ins>}
</pre></blockquote>

<ol>
<blockquote><pre>
<ins>constexpr atomic() noexcept = default;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Initializes the <tt>atomic</tt> object to an empty null value.
</ins></li>


<blockquote><pre>
<ins>atomic(weak_ptr&lt;T&gt; desired) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Initializes the object with the value <tt>desired</tt>.
Initialization is not an atomic operation (4.7). [ <i>Note:</i> It is possible
to have an access to an atomic object <tt>A</tt> race with its construction,
for example by communicating the address of the just-constructed object
<tt>A</tt> to another thread via <tt>memory_order_relaxed</tt> operations on a
suitable atomic pointer variable, and then immediately accessing <tt>A</tt> in
the receiving thread. This results in undefined behavior. <i>&mdash; end note</i> ]
</ins></li>


<blockquote><pre>
<ins>void store(weak_ptr&lt;T&gt; desired, memory_order order = memory_order_seq_cst) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Requires:</i> The order argument shall not be <tt>memory_order_consume</tt>,
<tt>memory_order_acquire</tt>, nor <tt>memory_order_acq_rel</tt>.
</ins></li>

<li><ins>
<i>Effects:</i> Atomically replaces the value pointed to by <tt>this</tt> with
the value of <tt>desired</tt> as if by <tt>p-&gt;swap(desired)</tt>. Memory is
affected according to the value of
<tt>order</tt>.
</ins></li>


<blockquote><pre>
<ins>void operator=(weak_ptr&lt;T&gt; desired) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Equivalent to: <tt>store(desired)</tt>.
</ins></li>


<blockquote><pre>
<ins>weak_ptr<T> load(memory_order order = memory_order_seq_cst) const noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Requires:</i> <tt>order</tt> shall not be <tt>memory_order_release</tt> or
<tt>memory_order_acq_rel</tt>.
</ins></li>

<li><ins>
<i>Effects:</i> Memory is affected according to the value of <tt>order</tt>.
</ins></li>

<li><ins>
<i>Returns:</i> Atomically returns <tt>*p</tt>.
</ins></li>


<blockquote><pre>
<ins>operator weak_ptr&lt;T&gt;() const noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Equivalent to: <tt>return load();</tt>
</ins></li>


<blockquote><pre>
<ins>weak_ptr&lt;T&gt; exchange(weak_ptr&lt;T&gt; desired, memory_order = memory_order_seq_cst) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Atomically replaces <tt>p</tt> with <tt>desired</tt> as if by
<tt>p-&gt;swap(desired)</tt>. Memory is affected according to the value of
<tt>order</tt>.  This is an atomic read-modify-write operation (4.7.1
[intro.races]).
</ins></li>

<li><ins>
<i>Returns:</i> Atomically returns the value of <tt>*p</tt> immediately before the effects.
</ins></li>


<blockquote><pre>
<ins>bool compare_exchange_weak(weak_ptr&lt;T&gt;&amp; expected, const weak_ptr&lt;T&gt;&amp; desired,</ins>
      <ins>memory_order success, memory_order failure) noexcept;</ins>
<ins>bool compare_exchange_weak(weak_ptr&lt;T&gt;&amp; expected, weak_ptr&lt;T&gt;&amp;&amp; desired,</ins>
      <ins>memory_order success, memory_order failure) noexcept;</ins>
<ins>bool compare_exchange_strong(weak_ptr&lt;T&gt;&amp; expected, const weak_ptr&lt;T&gt;&amp; desired,</ins>
      <ins>memory_order success, memory_order failure) noexcept;</ins>
<ins>bool compare_exchange_strong(weak_ptr&lt;T&gt;&amp; expected, weak_ptr&lt;T&gt;&amp;&amp; desired,</ins>
      <ins>memory_order success, memory_order failure) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Requires:</i> <tt>failure</tt> shall not be <tt>memory_order_release</tt>
nor <tt>memory_order_acq_rel</tt>.
</ins></li>

<li><ins>
<i>Effects:</i> If <tt>p</tt> is equivalent to <tt>expected</tt>, assigns
<tt>desired</tt> to <tt>p</tt> and has synchronization semantics corresponding
to the value of <tt>success</tt>, otherwise assigns <tt>p</tt> to
<tt>expected</tt> and has synchronization semantics corresponding to the value
of <tt>failure</tt>.
</ins></li>

<li><ins>
<i>Returns:</i> <tt>true</tt> if <tt>p</tt> was equivalent to <tt>expected</tt>,
<tt>false</tt> otherwise.
</ins></li>

<li><ins>
<i>Remarks:</i> Two <tt>weak_ptr</tt> objects are equivalent if they store
the same pointer value and either share ownership, or both are empty.  The weak
form may fail spuriously. See 32.6.1.
</ins></li>

<li><ins>
If the operation returns <tt>true</tt>, <tt>expected</tt> is not accessed after
the atomic update and the operation is an atomic read-modify-write operation
(4.7) on the memory pointed to by this. Otherwise, the operation is an atomic
load operation on that memory, and <tt>expected</tt> is updated with the
existing value read from the <tt>atomic</tt> object in the attempted atomic
update.  The <tt>use_count</tt> update corresponding to the write to
<tt>expected</tt> is part of the atomic operation.  The write to
<tt>expected</tt> itself is not required to be part of the atomic operation.
<li><ins>

<li><ins>
If the <tt>desired</tt> value is passed by rvalue reference and the operation
returns <tt>true</tt>, then <tt>desired</tt> is empty after the atomic update
step.
</li></ins>



<blockquote><pre>
<ins>bool compare_exchange_weak(weak_ptr&lt;T&gt;&amp; expected, const weak_ptr&lt;T&gt;&amp; desired,</ins>
      <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Equivalent to: <tt>return compare_exchange_weak(expected, desired, order, fail_order);</tt>
where <tt>fail_order</tt> is the same as <tt>order</tt> except that a value of
<tt>memory_order_acq_rel</tt> shall be replaced by the value
<tt>memory_order_acquire</tt> and a value of <tt>memory_order_release</tt>
shall be replaced by the value <tt>memory_order_relaxed</tt>.
</ins></li>

<blockquote><pre>
<ins>bool compare_exchange_weak(weak_ptr&lt;T&gt;&amp; expected, weak_ptr&lt;T&gt;&amp;&amp; desired,</ins>
      <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Equivalent to: <tt>return compare_exchange_weak(expected, std::move(desired), order, fail_order);</tt>
where <tt>fail_order</tt> is the same as <tt>order</tt> except that a value of
<tt>memory_order_acq_rel</tt> shall be replaced by the value
<tt>memory_order_acquire</tt> and a value of <tt>memory_order_release</tt>
shall be replaced by the value <tt>memory_order_relaxed</tt>.
</ins></li>

<blockquote><pre>
<ins>bool compare_exchange_strong(weak_ptr&lt;T&gt;&amp; expected, const weak_ptr&lt;T&gt;&amp; desired,</ins>
      <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Equivalent to: <tt>return compare_exchange_strong(expected, desired, order, fail_order);</tt>
where <tt>fail_order</tt> is the same as <tt>order</tt> except that a value of
<tt>memory_order_acq_rel</tt> shall be replaced by the value
<tt>memory_order_acquire</tt> and a value of <tt>memory_order_release</tt>
shall be replaced by the value <tt>memory_order_relaxed</tt>.
</ins></li>

<blockquote><pre>
<ins>bool compare_exchange_strong(weak_ptr&lt;T&gt;&amp; expected, weak_ptr&lt;T&gt;&amp;&amp; desired,</ins>
      <ins>memory_order order = memory_order_seq_cst) noexcept;</ins>
</pre></blockquote>

<li><ins>
<i>Effects:</i> Equivalent to: <tt>return compare_exchange_strong(expected, std::move(desired), order, fail_order);</tt>
where <tt>fail_order</tt> is the same as <tt>order</tt> except that a value of
<tt>memory_order_acq_rel</tt> shall be replaced by the value
<tt>memory_order_acquire</tt> and a value of <tt>memory_order_release</tt>
shall be replaced by the value <tt>memory_order_relaxed</tt>.
</ins></li>
</ol>
</blockquote>

<p>
Move the old atomic support for shated pointers into Annex D:
</p>

<blockquote>
<h4><del>23.11.2.6 <tt>shared_ptr</tt> atomic access [util.smartptr.shared.atomic]</del></h4>
<ol>
<li><del>
Concurrent access to a <tt>shared_ptr</tt> object from multiple threads does
not introduce a data race if the access is done exclusively via the functions
in this section and the instance is passed as their first argument.
</del></li>
<li><del>
The meaning of the arguments of type <tt>memory_order</tt> is explained in 32.4.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>bool atomic_is_lock_free(const shared_ptr&lt;T&gt;* p);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <tt>p</tt> shall not be null.
</del></li>
<li><del>
<i>Returns:</i> <tt>true</tt> if atomic access to <tt>*p</tt> is lock-free, <tt>false</tt> otherwise.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>shared_ptr<T> atomic_load(const shared_ptr<T>* p);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <tt>p</tt> shall not be null.
</del></li>
<li><del>
<i>Returns:</i> <tt>atomic_load_explicit(p, memory_order_seq_cst)</tt>.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* p, memory_order mo);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <tt>p</tt> shall not be null.
</del></li>
<li><del>
<i>Requires:</i> <tt>mo</tt> shall not be <tt>memory_order_release</tt> or <tt>memory_order_acq_rel</tt>.
</del></li>
<li><del>
<i>Returns:</i> <tt>*p</tt>.
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>void atomic_store(shared_ptr<T>* p, shared_ptr<T> r);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <tt>p</tt> shall not be null.
</del></li>
<li><del>
<i>Effects:</i> As if by <tt>atomic_store_explicit(p, r, memory_order_seq_cst)</tt>.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>void atomic_store_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <tt>p</tt> shall not be null.
</del></li>
<li><del>
<i>Requires:</i> <tt>mo</tt> shall not be <tt>memory_order_acquire</tt> or <tt>memory_order_acq_rel</tt>.
</del></li>
<li><del>
<i>Effects:</i> As if by <tt>p-&gt;swap(r)</tt>.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>shared_ptr<T> atomic_exchange(shared_ptr<T>* p, shared_ptr<T> r);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <tt>p</tt> shall not be null.
</del></li>
<li><del>
<i>Returns:</i> <tt>atomic_exchange_explicit(p, r, memory_order_seq_cst)</tt>.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>shared_ptr<T> atomic_exchange_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <tt>p</tt> shall not be null.
</del></li>
<li><del>
<i>Effects:</i> As if by <tt>p-&gt;swap(r)</tt>.
</del></li>
<li><del>
<i>Returns:</i> The previous value of <tt>*p</tt>.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_weak(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);</del>
</pre></blockquote>
<li><del>
<i>Returns:</i>
     <tt>atomic_compare_exchange_strong_explicit(p, v, w, memory_order_seq_cst, memory_order_seq_cst)</tt>.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_strong(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <tt>p</tt> shall not be null.
</del></li>
<li><del>
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template<class T><del>
  <del>bool atomic_compare_exchange_weak_explicit(<del>
    <del>shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w,<del>
    <del>memory_order success, memory_order failure);<del>
<del>template<class T><del>
  <del>bool atomic_compare_exchange_strong_explicit(<del>
    <del>shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w,<del>
    <del>memory_order success, memory_order failure);<del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <tt>p</tt> shall not be null and <tt>v</tt> shall not be null. The <tt>failure</tt> argument
shall not be <tt>memory_order_release</tt> nor <tt>memory_order_acq_rel</tt>.
</del></li>
<li><del>
<i>Effects:</i> If <tt>*p</tt> is equivalent to <tt>*v</tt>, assigns <tt>w</tt> to <tt>*p</tt> and has synchronization
semantics corresponding to the value of <tt>success</tt>, otherwise assigns <tt>*p</tt> to <tt>*v</tt> and
has synchronization semantics corresponding to the value of <tt>failure</tt>.
</del></li>
<li><del>
<i>Returns:</i> <tt>true</tt> if <tt>*p</tt> was equivalent to <tt>*v</tt>, <tt>false</tt> otherwise.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>
<li><del>
<i>Remarks:</i> Two <tt>shared_ptr</tt> objects are equivalent if they store the same pointer
value and share ownership. The weak form may fail spuriously. See 32.6.1.
</del></li>
</ol>
</blockquote>

<blockquote>

<h4><ins>D.14.x <tt>shared_ptr</tt> atomic access [depr.util.smartptr.shared.atomic]</ins></h4>
<blockquote><pre>
<ins>namespace std {</ins>
<ins>// D.14.x <tt>shared_ptr</tt> atomic access</ins>
<ins>template &lt;class T&gt;</ins>
  <ins>bool atomic_is_lock_free(const shared_ptr&lt;T&gt;* p);</ins>

<ins>template &lt;class T&gt;</ins>
  <ins>shared_ptr&lt;T&gt; atomic_load(const shared_ptr&lt;T&gt;* p);</ins>
<ins>template &lt;class T&gt;</ins>
  <ins>shared_ptr&lt;T&gt; atomic_load_explicit(const shared_ptr&lt;T&gt;* p, memory_order mo);</ins>

<ins>template &lt;class T&gt;</ins>
  <ins>void atomic_store(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r);</ins>
<ins>template &lt;class T&gt;</ins>
  <ins>void atomic_store_explicit(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r, memory_order mo);</ins>

<ins>template &lt;class T&gt;</ins>
  <ins>shared_ptr&lt;T&gt; atomic_exchange(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r);</ins>
<ins>template &lt;class T&gt;</ins>
  <ins>shared_ptr&lt;T&gt; atomic_exchange_explicit(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r, memory_order mo);</ins>

<ins>template &lt;class T&gt;</ins>
  <ins>bool atomic_compare_exchange_weak(</ins>
    <ins>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w);</ins>
<ins>template &lt;class T&gt;</ins>
  <ins>bool atomic_compare_exchange_strong(</ins>
    <ins>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w);</ins>
<ins>template &lt;class T&gt;</ins>
  <ins>bool atomic_compare_exchange_weak_explicit(</ins>
    <ins>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w,</ins>
    <ins>memory_order success, memory_order failure);</ins>
<ins>template &lt;class T&gt;</ins>
  <ins>bool atomic_compare_exchange_strong_explicit(</ins>
    <ins>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w,</ins>
    <ins>memory_order success, memory_order failure);</ins>
<ins>}</ins>
</pre></blockquote>

<ol>
<li><ins>
Concurrent access to a <tt>shared_ptr</tt> object from multiple threads does
not introduce a data race if the access is done exclusively via the functions
in this section and the instance is passed as their first argument.
</ins></li>
<li><ins>
The meaning of the arguments of type <tt>memory_order</tt> is explained in 32.4.
</ins></li>

<blockquote><pre>
<ins>template&lt;class T&gt;</ins>
  <ins>bool atomic_is_lock_free(const shared_ptr&lt;T&gt;* p);</ins>
</pre></blockquote>
<li><ins>
<i>Requires:</i> <tt>p</tt> shall not be null.
</ins></li>
<li><ins>
<i>Returns:</i> <tt>true</tt> if atomic access to <tt>*p</tt> is lock-free, <tt>false</tt> otherwise.
</ins></li>
<li><ins>
<i>Throws:</i> Nothing.
</ins></li>

<blockquote><pre>
<ins>template&lt;class T&gt;</ins>
  <ins>shared_ptr<T> atomic_load(const shared_ptr<T>* p);</ins>
</pre></blockquote>
<li><ins>
<i>Requires:</i> <tt>p</tt> shall not be null.
</ins></li>
<li><ins>
<i>Returns:</i> <tt>atomic_load_explicit(p, memory_order_seq_cst)</tt>.
</ins></li>
<li><ins>
<i>Throws:</i> Nothing.
</ins></li>

<blockquote><pre>
<ins>template&lt;class T&gt;</ins>
  <ins>shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* p, memory_order mo);</ins>
</pre></blockquote>
<li><ins>
<i>Requires:</i> <tt>p</tt> shall not be null.
</ins></li>
<li><ins>
<i>Requires:</i> <tt>mo</tt> shall not be <tt>memory_order_release</tt> or <tt>memory_order_acq_rel</tt>.
</ins></li>
<li><ins>
<i>Returns:</i> <tt>*p</tt>.
</ins></li>
<li><ins>
<i>Throws:</i> Nothing.
</ins></li>

<blockquote><pre>
<ins>template&lt;class T&gt;</ins>
  <ins>void atomic_store(shared_ptr<T>* p, shared_ptr<T> r);</ins>
</pre></blockquote>
<li><ins>
<i>Requires:</i> <tt>p</tt> shall not be null.
</ins></li>
<li><ins>
<i>Effects:</i> As if by <tt>atomic_store_explicit(p, r, memory_order_seq_cst)</tt>.
</ins></li>
<li><ins>
<i>Throws:</i> Nothing.
</ins></li>

<blockquote><pre>
<ins>template&lt;class T&gt;</ins>
  <ins>void atomic_store_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);</ins>
</pre></blockquote>
<li><ins>
<i>Requires:</i> <tt>p</tt> shall not be null.
</ins></li>
<li><ins>
<i>Requires:</i> <tt>mo</tt> shall not be <tt>memory_order_acquire</tt> or <tt>memory_order_acq_rel</tt>.
</ins></li>
<li><ins>
<i>Effects:</i> As if by <tt>p-&gt;swap(r)</tt>.
</ins></li>
<li><ins>
<i>Throws:</i> Nothing.
</ins></li>

<blockquote><pre>
<ins>template&lt;class T&gt;</ins>
  <ins>shared_ptr<T> atomic_exchange(shared_ptr<T>* p, shared_ptr<T> r);</ins>
</pre></blockquote>
<li><ins>
<i>Requires:</i> <tt>p</tt> shall not be null.
</ins></li>
<li><ins>
<i>Returns:</i> <tt>atomic_exchange_explicit(p, r, memory_order_seq_cst)</tt>.
</ins></li>
<li><ins>
<i>Throws:</i> Nothing.
</ins></li>

<blockquote><pre>
<ins>template&lt;class T&gt;</ins>
  <ins>shared_ptr<T> atomic_exchange_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);</ins>
</pre></blockquote>
<li><ins>
<i>Requires:</i> <tt>p</tt> shall not be null.
</ins></li>
<li><ins>
<i>Effects:</i> As if by <tt>p-&gt;swap(r)</tt>.
</ins></li>
<li><ins>
<i>Returns:</i> The previous value of <tt>*p</tt>.
</ins></li>
<li><ins>
<i>Throws:</i> Nothing.
</ins></li>

<blockquote><pre>
<ins>template&lt;class T&gt;</ins>
  <ins>bool atomic_compare_exchange_weak(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);</ins>
</pre></blockquote>
<li><ins>
<i>Returns:</i>
     <tt>atomic_compare_exchange_strong_explicit(p, v, w, memory_order_seq_cst, memory_order_seq_cst)</tt>.
</ins></li>

<blockquote><pre>
<ins>template&lt;class T&gt;</ins>
  <ins>bool atomic_compare_exchange_strong(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);</ins>
</pre></blockquote>
<li><ins>
<i>Requires:</i> <tt>p</tt> shall not be null.
</ins></li>
<li><ins>
</ins></li>
<li><ins>
<i>Throws:</i> Nothing.
</ins></li>

<blockquote><pre>
<ins>template<class T><ins>
  <ins>bool atomic_compare_exchange_weak_explicit(<ins>
    <ins>shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w,<ins>
    <ins>memory_order success, memory_order failure);<ins>
<ins>template<class T><ins>
  <ins>bool atomic_compare_exchange_strong_explicit(<ins>
    <ins>shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w,<ins>
    <ins>memory_order success, memory_order failure);<ins>
</pre></blockquote>
<li><ins>
<i>Requires:</i> <tt>p</tt> shall not be null and <tt>v</tt> shall not be null. The <tt>failure</tt> argument
shall not be <tt>memory_order_release</tt> nor <tt>memory_order_acq_rel</tt>.
</ins></li>
<li><ins>
<i>Effects:</i> If <tt>*p</tt> is equivalent to <tt>*v</tt>, assigns <tt>w</tt> to <tt>*p</tt> and has synchronization
semantics corresponding to the value of <tt>success</tt>, otherwise assigns <tt>*p</tt> to <tt>*v</tt> and
has synchronization semantics corresponding to the value of <tt>failure</tt>.
</ins></li>
<li><ins>
<i>Returns:</i> <tt>true</tt> if <tt>*p</tt> was equivalent to <tt>*v</tt>, <tt>false</tt> otherwise.
</ins></li>
<li><ins>
<i>Throws:</i> Nothing.
</ins></li>
<li><ins>
<i>Remarks:</i> Two <tt>shared_ptr</tt> objects are equivalent if they store the same pointer
value and share ownership. The weak form may fail spuriously. See 32.6.1.
</ins></li>
</ol>



<h2><a name="6.0">6 Acknowledements</h2>
<p>
Thanks to Herb Sutter, not only for the original proposal that was adopted for
the TS, but especially for being available on short notice to advise on the
history and rationale of the feature for this paper.  Thanks to Stephan T.
Lavavej for a detailed review of an early draft of this paper that improved it
in many ways.
</p>


<h2><a name="7.0">7 References</h2>
<ul>
  <li>
    <a href="https://cplusplus.github.io/LWG/lwg-active.html#2334">LWG #2334</a>
    <tt>atomic</tt>'s default constructor requires "uninitialized" state even for types with non-trivial default-constructor
  </li>
  <li>
    <a href="https://cplusplus.github.io/LWG/lwg-active.html#2980">LWG #2980</a>
    Cannot <tt>compare_exchange</tt> empty pointers
  </li>
  <li>
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4058.pdf">N4058</a>,
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4162.pdf">N4162</a>,
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4260.pdf">N4260</a>
    Atomic Smart Pointers,
    Herb Sutter
  </li>
  <li>
    <a href="http://www.open-std.org/jtc1/sc22/wg21/prot/14882fdis/n4577">N4577</a>
    Technical Specification for C++ Extensions for Concurrency,
    Artur Laksberg
  </li>
</ul>


</body>
</html>
