<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 834: unique_ptr::pointer requirements underspecified</title>
<meta property="og:title" content="Issue 834: unique_ptr::pointer requirements underspecified">
<meta property="og:description" content="C++ library issue. Status: Resolved">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue834.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#Resolved">Resolved</a> status.</em></p>
<h3 id="834"><a href="lwg-defects.html#834">834</a>. <code>unique_ptr::pointer</code> requirements underspecified</h3>
<p><b>Section:</b> 20.3.1.3 <a href="https://wg21.link/unique.ptr.single">[unique.ptr.single]</a> <b>Status:</b> <a href="lwg-active.html#Resolved">Resolved</a>
 <b>Submitter:</b> Daniel Kr&uuml;gler <b>Opened:</b> 2008-05-14 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View other</b> <a href="lwg-index-open.html#unique.ptr.single">active issues</a> in [unique.ptr.single].</p>
<p><b>View all other</b> <a href="lwg-index.html#unique.ptr.single">issues</a> in [unique.ptr.single].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#Resolved">Resolved</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Issue <a href="lwg-defects.html#673" title="unique_ptr update (Status: CD1)">673</a><sup><a href="https://cplusplus.github.io/LWG/issue673" title="Latest snapshot">(i)</a></sup> (including recent updates by <a href="lwg-defects.html#821" title="Minor cleanup : unique_ptr (Status: C++11)">821</a><sup><a href="https://cplusplus.github.io/LWG/issue821" title="Latest snapshot">(i)</a></sup>) proposes a useful
extension point for <code>unique_ptr</code> by granting support for an optional
<code>deleter_type::pointer</code> to act as pointer-like replacement for <code>element_type*</code>
(In the following: <code>pointer</code>).
</p>
<p>
Unfortunately no requirements are specified for the type <code>pointer</code> which has
impact on at least two key features of <code>unique_ptr</code>:
</p>

<ol>
<li>Operational fail-safety.</li>
<li>(Well-)Definedness of expressions.</li>
</ol>

<p>
The <code>unique_ptr</code> specification makes great efforts to require that essentially <em>all</em>
operations cannot throw and therefore adds proper wording to the affected
operations of the deleter as well. If user-provided <code>pointer</code>-emulating types
("smart pointers") will be allowed, either <em>all</em> throw-nothing clauses have to
be replaced by weaker "An exception is thrown only if <code>pointer</code>'s {op} throws
an exception"-clauses or it has to be said explicitly that all used
operations of <code>pointer</code> are required <em>not</em> to throw. I understand the main 
focus of <code>unique_ptr</code> to be as near as possible to the advantages of native pointers which cannot
fail and thus strongly favor the second choice. Also, the alternative position
would make it much harder to write safe and simple template code for
<code>unique_ptr</code>. Additionally, I assume that a general statement need to be given
that all of the expressions of <code>pointer</code> used to define semantics are required to
be well-formed and well-defined (also as back-end for <a href="lwg-defects.html#762" title="std::unique_ptr requires complete type? (Status: CD1)">762</a><sup><a href="https://cplusplus.github.io/LWG/issue762" title="Latest snapshot">(i)</a></sup>).
</p>

<p><i>[
Sophia Antipolis:
]</i></p>


<blockquote>
<p>
Howard: We maybe need a core concept <code>PointerLike</code>, but we don't need the
arithmetic (see <code>shared_ptr</code> vs. <code>vector&lt;T&gt;::iterator</code>.
</p>
<p>
Howard will go through and enumerate the individual requirements wrt. <code>pointer</code> for each member function.
</p>
</blockquote>

<p><i>[
2009-07 Frankfurt:
]</i></p>


<blockquote><p>
Move to Ready.
</p></blockquote>

<p><i>[
2009-10-15 Alisdair pulls from Ready:
]</i></p>


<blockquote>
<p>
I hate to pull an issue out of Ready status, but I don't think 834 is
fully baked yet.
</p>

<p>
For reference the proposed resolution is to add the following words:
</p>

<blockquote><p>
<code>unique_ptr&lt;T, D&gt;::pointer</code>'s operations shall be
well-formed, shall have well defined behavior, and shall not throw
exceptions.
</p></blockquote>

<p>
This leaves me with a big question : which operations?
</p>

<p>
Are all pointer operations required to be nothrow, including operations
that have nothing to do with interactions with <code>unique_ptr</code>?  This was
much simpler with concepts where we could point to operations within a
certain concept, and so nail down the interactions.
</p>
</blockquote>

<p><i>[
2009-10-15 Daniel adds:
]</i></p>


<blockquote><p>
I volunteer to prepare a more fine-grained solution, but I would like
to ask for feedback that helps me doing so. If this question is asked
early in the meeting I might be able to fix it within the week, but I
cannot promise that now.
</p></blockquote>

<p><i>[
2009-10 Santa Cruz:
]</i></p>


<blockquote><p>
Leave in open. Daniel to provide wording as already suggested.
</p></blockquote>

<p><i>[
2009-12-22 Daniel provided wording and rationale.
]</i></p>


<p><i>[
2010 Pittsburgh:  Moved to NAD Editorial.  Rationale added below.
]</i></p>




<p><b>Rationale:</b></p>
<p>
The here proposed resolution has considerable overlap with the requirements that
are used in the allocator requirements.
</p>

<p>
This might be a convincing argument to isolate the common subset into one
requirement. The reason I did not do that is basically because we might find out
that they are either over-constraining or under-constraining at this late point
of specification. Note also that as a result of the idea of a general
requirement set I added the requirement:
</p>

<blockquote><p>
A default-initialized object may have a singular value
</p></blockquote>

<p>
even though this does not play a relevant role for <code>unique_ptr</code>.
</p>

<p>
One further characteristics of the resolution is that availability of relational
operators of <code>unique_ptr&lt;T, D&gt;::pointer</code> is not part of the basic
requirements, which is in sync with the allocator requirements on pointer-like
(this means that <code>unique_ptr</code> can hold a <code>void_pointer</code> or
<code>const_void_pointer</code>).
</p>

<p>
Solved by
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3073.html">N3073</a>.
</p>



<p id="res-834"><b>Proposed resolution:</b></p>

<ol>

<li>
<p>
Change 20.3.1.3 <a href="https://wg21.link/unique.ptr.single">[unique.ptr.single]</a> p. 1 as indicated: <i>[The intent is to
replace the coupling between <code>T*</code> and the deleter's <code>operator()</code>
by a coupling between <code>unique_ptr&lt;T, D&gt;::pointer</code> and this
<code>operator()</code>]</i>
</p>

<blockquote><p>
1 - The default type for the template parameter <code>D</code> is
<code>default_delete</code>. A client-supplied template argument <code>D</code> shall be
a function pointer or functor for which, given a value <code>d</code> of type
<code>D</code> and a <del>pointer</del> <ins>value</ins> <code>ptr</code> of type
<code><del>T*</del> <ins>unique_ptr&lt;T, D&gt;::pointer</ins></code>, the
expression <code>d(ptr)</code> is valid and has the effect of deallocating the
pointer as appropriate for that deleter. <code>D</code> may also be an
lvalue-reference to a deleter.
</p></blockquote>
</li>

<li>
<p>
Change 20.3.1.3 <a href="https://wg21.link/unique.ptr.single">[unique.ptr.single]</a> p. 3 as indicated:
</p>

<blockquote>
<p>
3 - If the type <code>remove_reference&lt;D&gt;::type::pointer</code> exists, then
<code>unique_ptr&lt;T, D&gt;::pointer</code> shall be a synonym for
<code>remove_reference&lt;D&gt;::type::pointer</code>. Otherwise
<code>unique_ptr&lt;T, D&gt;::pointer</code> shall be a synonym for <code>T*</code>. The
type <code>unique_ptr&lt;T, D&gt;::pointer</code> shall <del>be</del> <ins>satisfy
the requirements of <code>EqualityComparable</code>,
<code>DefaultConstructible</code>,</ins> <code>CopyConstructible</code> <del>(Table 34)
and</del><ins>,</ins> <code>CopyAssignable</code> <del>(Table 36)</del><ins>,
<code>Swappable</code>, and <code>Destructible</code> (16.4.4.2 <a href="https://wg21.link/utility.arg.requirements">[utility.arg.requirements]</a>). A default-initialized object may have a
singular value.  A value-initialized object produces the null value of the type.
The null value shall be equivalent only to itself. An object of this type can be
copy-initialized with a value of type <code>nullptr_t</code>, compared for equality
with a value of type <code>nullptr_t</code>, and assigned a value of type
<code>nullptr_t</code>. The effect shall be as if a value-initialized object had
been used in place of the null pointer constant. An object <code>p</code> of this
type can be contextually converted to <code>bool</code>. The effect shall be as if
<code>p != nullptr</code> had been evaluated in place of <code>p</code>. No operation on
this type which is part of the above mentioned requirements shall exit via an
exception.
</ins>
</p>
<p><ins>
[<i>Note:</i> Given an allocator type <code>X</code> (16.4.4.6 <a href="https://wg21.link/allocator.requirements">[allocator.requirements]</a>), the types <code>X::pointer</code>,
<code>X::const_pointer</code>, <code>X::void_pointer</code>, and
<code>X::const_void_pointer</code> may be used as <code>unique_ptr&lt;T,
D&gt;::pointer</code> &mdash; <i>end note</i>]
</ins></p>

<p><ins>
In addition to being available via inclusion of the <code>&lt;utility&gt;</code>
header, the <code>swap</code> function template in 22.2.2 <a href="https://wg21.link/utility.swap">[utility.swap]</a> is
also available within the definition of <code>unique_ptr</code>'s <code>swap</code>
function.
</ins></p>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.3.2 <a href="https://wg21.link/unique.ptr.single.ctor">[unique.ptr.single.ctor]</a> p. 2+3 as indicated: <i>[The first
change ensures that we explicitly say, how the stored pointer is initialized.
This is important for a <code>constexpr</code> function, because this may make a
difference for user-defined pointer-like types]</i>
</p>

<blockquote><pre>
constexpr unique_ptr();
</pre>
<blockquote>
<p>...</p>
<p>
2 - <i>Effects:</i> Constructs a <code>unique_ptr</code> which owns nothing<ins>,
value-initializing the stored pointer</ins>.
</p>

<p>
3 - <i>Postconditions:</i> <code>get() == <del>0</del> <ins>nullptr</ins></code>.
</p>
</blockquote>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.3.2 <a href="https://wg21.link/unique.ptr.single.ctor">[unique.ptr.single.ctor]</a> p. 6+7 as indicated: <i>[This is a
step-by-fix to ensure consistency to the changes of
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2976.html">N2976</a>]</i>
</p>

<blockquote><pre>
unique_ptr(pointer p);
</pre>
<blockquote>
<p>...</p>
<p>
6 - <i>Effects:</i> Constructs a <code>unique_ptr</code> which owns <code>p</code><ins>,
initializing the stored pointer with <code>p</code></ins>.
</p>

<p>
7 - <i>Postconditions:</i> <code>get() == p</code>. <code>get_deleter()</code> returns a
reference to a <del>default constructed</del> <ins>value-initialized</ins>
deleter <code>D</code>.
</p>
</blockquote>
</blockquote>
</li>

<li>
<p>
Insert a new effects clause in 20.3.1.3.2 <a href="https://wg21.link/unique.ptr.single.ctor">[unique.ptr.single.ctor]</a> just
before p. 14: <i>[The intent is to fix the current lack of specification in
which way the stored pointer is initialized]</i>
</p>

<blockquote><pre>
unique_ptr(pointer p, <i><del>implementation-defined</del> <ins>see below</ins></i> d1);
unique_ptr(pointer p, <i><del>implementation-defined</del> <ins>see below</ins></i> d2);
</pre>
<blockquote>
<p>...</p>
<p><ins>
<i>Effects:</i> Constructs a <code>unique_ptr</code> which owns <code>p</code>,
initializing the stored pointer with <code>p</code> and the initializing the deleter
as described above.
</ins></p>

<p>
14 - <i>Postconditions:</i> <code>get() == p</code>. <code>get_deleter()</code> returns a
reference to the internally stored deleter. If <code>D</code> is a reference type
then <code>get_deleter()</code> returns a reference to the lvalue <code>d</code>.
</p>
</blockquote>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.3.2 <a href="https://wg21.link/unique.ptr.single.ctor">[unique.ptr.single.ctor]</a> p. 18+22 as indicated: <i>[The intent
is to clarify that the moved-from source must contain a null pointer, there is
no other choice left]</i>
</p>

<blockquote><pre>
unique_ptr(unique_ptr&amp;&amp; u);
</pre>
<blockquote>
<p>
[..]
</p>

<p>
18 - <i>Postconditions:</i> <code>get() == value u.get()</code> had before the
construction<ins> and <code>u.get() == nullptr</code></ins>. <code>get_deleter()</code>
returns a reference to the internally stored deleter which was constructed from
<code>u.get_deleter()</code>. If <code>D</code> is a reference type then
<code>get_deleter()</code> and <code>u.get_deleter()</code> both reference the same
lvalue deleter.
</p>

</blockquote>

<pre>
template &lt;class U, class E&gt; unique_ptr(unique_ptr&lt;U, E&gt;&amp;&amp; u);
</pre>

<blockquote>

<p>
[..]
</p>

<p>
22 - <i>Postconditions:</i> <code>get() == value u.get()</code> had before the
construction, modulo any required offset adjustments resulting from the cast
from <code>unique_ptr&lt;U, E&gt;::pointer</code> to <code>pointer</code><ins> and
<code>u.get() == nullptr</code></ins>. <code>get_deleter()</code> returns a reference to
the internally stored deleter which was constructed from
<code>u.get_deleter()</code>.
</p>
</blockquote>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.3.2 <a href="https://wg21.link/unique.ptr.single.ctor">[unique.ptr.single.ctor]</a> p. 20 as indicated: <i>[With the
possibility of user-defined pointer-like types the implication does only exist,
if those are built-in pointers. Note that this change should also be applied
with the acceptance of <a href="lwg-defects.html#950" title="unique_ptr converting ctor shouldn't accept array form (Status: Resolved)">950</a><sup><a href="https://cplusplus.github.io/LWG/issue950" title="Latest snapshot">(i)</a></sup>]</i>
</p>

<blockquote><pre>
template &lt;class U, class E&gt; unique_ptr(unique_ptr&lt;U, E&gt;&amp;&amp; u);
</pre>
<blockquote><p>
20 - <i>Requires:</i> If <code>D</code> is not a reference type, construction of the
deleter <code>D</code> from an rvalue of type <code>E</code> shall be well formed and
shall not throw an exception. If <code>D</code> is a reference type, then <code>E</code>
shall be the same type as <code>D</code> (diagnostic required). <code>unique_ptr&lt;U,
E&gt;::pointer</code> shall be implicitly convertible to <code>pointer</code>.
<del>[<i>Note:</i> These requirements imply that <code>T</code> and <code>U</code> are
complete types. &mdash; <i>end note</i>]</del>
</p></blockquote>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.3.3 <a href="https://wg21.link/unique.ptr.single.dtor">[unique.ptr.single.dtor]</a> p. 2 as indicated:
</p>

<blockquote><pre>
~unique_ptr();
</pre>
<blockquote>
<p>...</p>
<p>
2 - <i>Effects:</i> If <code>get() == <del>0</del> <ins>nullptr</ins></code> there
are no effects. Otherwise <code>get_deleter()(get())</code>.
</p>
</blockquote>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.3.4 <a href="https://wg21.link/unique.ptr.single.asgn">[unique.ptr.single.asgn]</a> p. 3+8 as indicated: <i>[The intent is to
clarify that the moved-from source must contain a null pointer, there
is no other choice left]</i>
</p>

<blockquote><pre>
unique_ptr&amp; operator=(unique_ptr&amp;&amp; u);
</pre>
<blockquote>
<p>[..]</p>
<p>
3 - <i>Postconditions:</i> This <code>unique_ptr</code> now owns the pointer which <code>u</code>
owned, and <code>u</code> no longer owns it<ins>, <code>u.get() == nullptr</code></ins>.
[<i>Note:</i> If <code>D</code> is a reference type, then the referenced lvalue deleters
are move assigned. &mdash; <i>end note</i>]
</p>
</blockquote>

<pre>
template &lt;class U, class E&gt; unique_ptr&amp; operator=(unique_ptr&lt;U, E&gt;&amp;&amp; u);
</pre>

<blockquote>
<p>[..]</p>

<p>
8 - <i>Postconditions:</i> This <code>unique_ptr</code> now owns the pointer which
<code>u</code> owned, and <code>u</code> no longer owns it<ins>, <code>u.get() ==
nullptr</code></ins>.
</p>
</blockquote>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.3.4 <a href="https://wg21.link/unique.ptr.single.asgn">[unique.ptr.single.asgn]</a> p. 6 as indicated: <i>[With the
possibility of user-defined pointer-like types the implication does only exist,
if those are built-in pointers. Note that this change should also be applied
with the acceptance of <a href="lwg-defects.html#950" title="unique_ptr converting ctor shouldn't accept array form (Status: Resolved)">950</a><sup><a href="https://cplusplus.github.io/LWG/issue950" title="Latest snapshot">(i)</a></sup>]</i>
</p>

<blockquote><pre>
template &lt;class U, class E&gt; unique_ptr&amp; operator=(unique_ptr&lt;U, E&gt;&amp;&amp; u);
</pre>
<blockquote>
<p>[..]</p>
<p>
6 - <i>Requires:</i> Assignment of the deleter <code>D</code> from an rvalue
<code>D</code> shall not throw an exception. <code>unique_ptr&lt;U,
E&gt;::pointer</code> shall be implicitly convertible to <code>pointer</code>.
<del>[<i>Note:</i> These requirements imply that <code>T</code> and <code>U</code> are
complete types. &mdash; <i>end note</i>]</del>
</p>
</blockquote>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.3.4 <a href="https://wg21.link/unique.ptr.single.asgn">[unique.ptr.single.asgn]</a> before p. 11 and p. 12 as
indicated: <i>[The first change is a simple typo fix]</i>
</p>

<blockquote><pre>
unique_ptr&amp; operator=(nullptr_t<del>}</del><ins>)</ins>;
</pre>

<blockquote>
<p>
11 - <i>Effects:</i> <code>reset()</code>.
</p>

<p>
12 - <i>Postcondition:</i> <code>get() == <del>0</del> <ins>nullptr</ins></code>
</p>
</blockquote>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.3.5 <a href="https://wg21.link/unique.ptr.single.observers">[unique.ptr.single.observers]</a> p. 1+4+12 as indicated:
</p>

<blockquote><pre>
typename add_lvalue_reference&lt;T&gt;::type operator*() const;
</pre>
<blockquote>
<p>
1 - <i>Requires:</i> <code>get() != <del>0</del> <ins>nullptr</ins></code>. <ins>The
variable definition <code>add_lvalue_reference&lt;T&gt;::type t = *get()</code>
shall be well formed, shall have well-defined behavior, and shall not exit via
an exception.</ins>
</p>
<p>
[..]
</p>

</blockquote>

<pre>
pointer operator-&gt;() const;
</pre>

<blockquote>
<p>
4 - <i>Requires:</i> <code>get() != <del>0</del> <ins>nullptr</ins></code>.
</p>

<p>
[..]
</p>

</blockquote>

<pre>
explicit operator bool() const;
</pre>

<blockquote><p>
12 - <i>Returns:</i> <code>get() != <del>0</del><ins>nullptr</ins></code>.
</p></blockquote>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.3.6 <a href="https://wg21.link/unique.ptr.single.modifiers">[unique.ptr.single.modifiers]</a> p. 1 as indicated:
</p>

<blockquote><pre>
pointer release();
</pre>

<blockquote><p>
1 - <i>Postcondition:</i> <code>get() == <del>0</del> <ins>nullptr</ins></code>.
</p></blockquote>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.3.6 <a href="https://wg21.link/unique.ptr.single.modifiers">[unique.ptr.single.modifiers]</a> p. 9 as indicated: <i>[The
intent is to ensure that potentially user-defined swaps are used. A side-step
fix and harmonization with the specification of the the deleter is realized.
Please note the additional requirement in bullet 2 of this proposed resolution
regarding the availability of the generic <code>swap</code> templates within the
member <code>swap</code> function.]</i>
</p>

<blockquote><pre>
void swap(unique_ptr&amp; u);
</pre>

<blockquote>
<p>
8 - <i>Requires:</i> The deleter <code>D</code> shall be <code>Swappable</code> and
shall not throw an exception under <code>swap</code>.
</p>

<p>
9 - <i>Effects:</i> The stored pointers of <code><ins>*</ins>this</code> and
<code>u</code> are exchanged <ins>by an unqualified call to non-member
<code>swap</code></ins>. The stored deleters are <del><code>swap</code>'d
(unqualified)</del> <ins>exchanged by an unqualified call to non-member
<code>swap</code></ins>.
</p>
</blockquote>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.4.4 <a href="https://wg21.link/unique.ptr.runtime.observers">[unique.ptr.runtime.observers]</a> p. 1 as indicated:
</p>

<blockquote><pre>
T&amp; operator[](size_t i) const;
</pre>
<blockquote><p>
<i>Requires:</i> <code>i &lt;</code> the size of the array to which the stored
pointer points. <ins>The variable definition <code>T&amp; t = get()[i]</code> shall
be well formed, shall have well-defined behavior, and shall not exit via an
exception.</ins>
</p></blockquote>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.4.5 <a href="https://wg21.link/unique.ptr.runtime.modifiers">[unique.ptr.runtime.modifiers]</a> p. 1 as indicated:
</p>

<blockquote><pre>
void reset(pointer p = pointer());
void reset(nullptr_t p);
</pre>

<blockquote><p>
1 - <i>Effects:</i> If <code>get() == <del>0</del> <ins>nullptr</ins></code> there
are no effects. Otherwise <code>get_deleter()(get())</code>.
</p></blockquote>
</blockquote>
</li>

<li>
<p>
Change 20.3.1.6 <a href="https://wg21.link/unique.ptr.special">[unique.ptr.special]</a> as indicated: <i>[We don't add the
relational operators to the basic requirement set, therefore we need special
handling here]</i>
</p>

<blockquote>
<pre>
template &lt;class T1, class D1, class T2, class D2&gt;
  bool operator==(const unique_ptr&lt;T1, D1&gt;&amp; x, const unique_ptr&lt;T2, D2&gt;&amp; y);
</pre>

<blockquote>
<p>
<ins><i>Requires:</i> The variable definition <code>bool b = x.get() == y.get();</code> shall be 
well formed, shall have well-defined behavior, and shall not exit via an exception.</ins>
</p>

<p>
2 - <i>Returns:</i> <code>x.get() == y.get()</code>.
</p>

<p><ins>
<i>Throws:</i> nothing.
</ins></p>
</blockquote>

<pre>
template &lt;class T1, class D1, class T2, class D2&gt;
  bool operator!=(const unique_ptr&lt;T1, D1&gt;&amp; x, const unique_ptr&lt;T2, D2&gt;&amp; y);
</pre>

<blockquote>
<p>
<ins>Requires: The variable definition <code>bool b = x.get() != y.get();</code>
shall be well formed, shall have well-defined behavior, and shall not exit via
an exception.</ins>
</p>

<p>
3 - <i>Returns:</i> <code>x.get() != y.get()</code>.
</p>

<p><ins>
<i>Throws:</i> nothing.
</ins></p>
</blockquote>

<pre>
template &lt;class T1, class D1, class T2, class D2&gt;
  bool operator&lt;(const unique_ptr&lt;T1, D1&gt;&amp; x, const unique_ptr&lt;T2, D2&gt;&amp; y);
</pre>

<blockquote>
<p>
<ins>Requires: The variable definition <code>bool b = x.get() &lt; y.get()</code>;
shall be well formed, shall have well-defined behavior, and shall not exit via
an exception.</ins>
</p>

<p>
4 - <i>Returns:</i> <code>x.get() &lt; y.get()</code>.
</p>

<p><ins>
<i>Throws:</i> nothing.
</ins></p>
</blockquote>

<pre>
template &lt;class T1, class D1, class T2, class D2&gt;
  bool operator&lt;=(const unique_ptr&lt;T1, D1&gt;&amp; x, const unique_ptr&lt;T2, D2&gt;&amp; y);
</pre>

<blockquote>
<p>
<ins>Requires: The variable definition <code>bool b = x.get() &lt;= y.get();</code>
shall be well formed, shall have well-defined behavior, and shall not exit via
an exception.</ins>
</p>

<p>
5 - <i>Returns:</i> <code>x.get() &lt;= y.get()</code>.
</p>

<p><ins>
<i>Throws:</i> nothing.
</ins></p>
</blockquote>

<pre>
template &lt;class T1, class D1, class T2, class D2&gt;
  bool operator&gt;(const unique_ptr&lt;T1, D1&gt;&amp; x, const unique_ptr&lt;T2, D2&gt;&amp; y);
</pre>

<blockquote>
<p>
<ins>Requires: The variable definition <code>bool b = x.get() &gt; y.get();</code>
shall be well formed, shall have well-defined behavior, and shall not exit via
an exception.</ins>
</p>

<p>
6 - <i>Returns:</i> <code>x.get() &gt; y.get()</code>.
</p>

<p><ins>
<i>Throws:</i> nothing.
</ins></p>
</blockquote>

<pre>
template &lt;class T1, class D1, class T2, class D2&gt;
  bool operator&gt;=(const unique_ptr&lt;T1, D1&gt;&amp; x, const unique_ptr&lt;T2, D2&gt;&amp; y);
</pre>

<blockquote>
<p>
<ins>Requires: The variable definition <code>bool b = x.get() &gt;= y.get();</code>
shall be well formed, shall have well-defined behavior, and shall not exit via
an exception.</ins>
</p>

<p>
7 - <i>Returns:</i> <code>x.get() &gt;= y.get()</code>.
</p>

<p><ins>
<i>Throws:</i> nothing.
</ins></p>
</blockquote>

</blockquote>
</li>

</ol>







</body>
</html>
