<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 463: auto_ptr usability issues</title>
<meta property="og:title" content="Issue 463: auto_ptr usability issues">
<meta property="og:description" content="C++ library issue. Status: NAD">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue463.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#NAD">NAD</a> status.</em></p>
<h3 id="463"><a href="lwg-closed.html#463">463</a>. <code>auto_ptr</code> usability issues</h3>
<p><b>Section:</b> 99 [auto.ptr] <b>Status:</b> <a href="lwg-active.html#NAD">NAD</a>
 <b>Submitter:</b> Rani Sharoni <b>Opened:</b> 2003-12-07 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all other</b> <a href="lwg-index.html#auto.ptr">issues</a> in [auto.ptr].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#NAD">NAD</a> status.</p>
<p><b>Discussion:</b></p>

<p>
TC1 CWG DR #84 effectively made the <code>template&lt;class Y&gt; operator auto_ptr&lt;Y&gt;()</code>
member of <code>auto_ptr</code> (20.4.5.3/4) obsolete.
</p>

<p>
The sole purpose of this obsolete conversion member is to enable copy
initialization base from r-value derived (or any convertible types like
cv-types) case:
</p>
<pre>
#include &lt;memory&gt;
using std::auto_ptr;

struct B {};
struct D : B {};

auto_ptr&lt;D&gt; source();
int sink(auto_ptr&lt;B&gt;);
int x1 = sink( source() ); // #1 EDG - no suitable copy constructor
</pre>

<p>
The excellent analysis of conversion operations that was given in the final
<code>auto_ptr</code> proposal
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1997/N1128.pdf)
explicitly specifies this case analysis (case 4). DR #84 makes the analysis
wrong and actually comes to forbid the loophole that was exploited by the
<code>auto_ptr</code> designers.
</p>

<p>
I didn't encounter any compliant compiler (e.g. EDG, GCC, BCC and VC) that
ever allowed this case. This is probably because it requires 3 user defined
conversions and in fact current compilers conform to DR #84.
</p>

<p>
I was surprised to discover that the obsolete conversion member actually has
negative impact of the copy initialization base from l-value derived
case:</p>
<pre>
auto_ptr&lt;D&gt; dp;
int x2 = sink(dp); // #2 EDG - more than one user-defined conversion applies
</pre>

<p>
I'm sure that the original intention was allowing this initialization using
the <code>template&lt;class Y&gt; auto_ptr(auto_ptr&lt;Y&gt;&amp; a)</code> constructor (20.4.5.1/4) but
since in this copy initialization it's merely user defined conversion (UDC)
and the obsolete conversion member is UDC with the same rank (for the early
overloading stage) there is an ambiguity between them.
</p>

<p>
Removing the obsolete member will have impact on code that explicitly
invokes it:
</p>
<pre>
int y = sink(source().operator auto_ptr&lt;B>());
</pre>

<p>
IMHO no one ever wrote such awkward code and the reasonable workaround for
#1 is:
</p>
<pre>
int y = sink( auto_ptr&lt;B>(source()) );
</pre>

<p>
I was even more surprised to find out that after removing the obsolete
conversion member the initialization was still ill-formed:
<code>int x3 = sink(dp); // #3 EDG - no suitable copy constructor</code>
</p>

<p>
This copy initialization semantically requires copy constructor which means
that both template conversion constructor and the <code>auto_ptr_ref</code> conversion
member (20.4.5.3/3) are required which is what was explicitly forbidden in
DR #84. This is a bit amusing case in which removing ambiguity results with
no candidates.
</p>

<p>
I also found exception safety issue with <code>auto_ptr</code> related to <code>auto_ptr_ref</code>:
</p>
<pre>
int f(auto_ptr&lt;B>, std::string);
auto_ptr&lt;B> source2();

// string constructor throws while auto_ptr_ref
// "holds" the pointer
int x4 = f(source2(), "xyz"); // #4
</pre>

<p>
The theoretic execution sequence that will cause a leak:
</p>
<ol>
<li>call auto_ptr&lt;B>::operator auto_ptr_ref&lt;B>()</li>
<li>call string::string(char const*) and throw</li>
</ol>

<p>
According to 20.4.5.3/3 and 20.4.5/2 the <code>auto_ptr_ref</code> conversion member
returns <code>auto_ptr_ref&lt;Y&gt;</code> that holds <code>*this</code> and this is another defect since
the type of <code>*this</code> is <code>auto_ptr&lt;X&gt;</code> where <code>X</code> might 
be different from <code>Y</code>. Several library vendors (e.g. SGI) implement 
<code>auto_ptr_ref&lt;Y&gt;</code> with <code>Y*</code> as member which
is much more reasonable. Other vendor implemented <code>auto_ptr_ref</code> as
defectively required and it results with awkward and catastrophic code:
<code>int oops = sink(auto_ptr&lt;B>(source())); // warning recursive on all control paths</code>
</p>

<p>
Dave Abrahams noticed that there is no specification saying that
<code>auto_ptr_ref</code> copy constructor can't throw.
</p>

<p>
My proposal comes to solve all the above issues and significantly simplify
<code>auto_ptr</code> implementation. One of the fundamental requirements from 
<code>auto_ptr</code> is that it can be constructed in an intuitive manner (i.e. 
like ordinary pointers) but with strict ownership semantics which yield that source
<code>auto_ptr</code> in initialization must be non-const. My idea is to add additional
constructor template with sole propose to generate ill-formed, diagnostic
required, instance for const auto_ptr arguments during instantiation of
declaration. This special constructor will not be instantiated for other
types which is achievable using 14.8.2/2 (SFINAE). Having this constructor
in hand makes the constructor <code>template&lt;class Y&gt; auto_ptr(auto_ptr&lt;Y> const&amp;)</code>
legitimate since the actual argument can't be const yet non const r-value
are acceptable.
</p>

<p>
This implementation technique makes the "private auxiliary class"
<code>auto_ptr_ref</code> obsolete and I found out that modern C++ compilers (e.g. EDG,
GCC and VC) consume the new implementation as expected and allow all
intuitive initialization and assignment cases while rejecting illegal cases
that involve const <code>auto_ptr</code> arguments.
</p>

<p>The proposed auto_ptr interface:</p>

<pre>
namespace std {
    template&lt;class X&gt; class auto_ptr {
    public:
        typedef X element_type;

        // 20.4.5.1 construct/copy/destroy:
        explicit auto_ptr(X* p=0) throw();
        auto_ptr(auto_ptr&amp;) throw();
        template&lt;class Y&gt; auto_ptr(auto_ptr&lt;Y&gt; const&amp;) throw();
        auto_ptr&amp; operator=(auto_ptr&amp;) throw();
        template&lt;class Y&gt; auto_ptr&amp; operator=(auto_ptr&lt;Y&gt;) throw();
        ~auto_ptr() throw();

        // 20.4.5.2 members:
        X&amp; operator*() const throw();
        X* operator->() const throw();
        X* get() const throw();
        X* release() throw();
        void reset(X* p=0) throw();

    private:
        template&lt;class U&gt;
        auto_ptr(U&amp; rhs, typename
unspecified_error_on_const_auto_ptr&lt;U&gt;::type = 0);
    };
}
</pre>

<p>
One compliant technique to implement the <code>unspecified_error_on_const_auto_ptr</code>
helper class is using additional private <code>auto_ptr</code> member class template like
the following:
</p>
<pre>
template&lt;typename T&gt; struct unspecified_error_on_const_auto_ptr;

template&lt;typename T&gt;
struct unspecified_error_on_const_auto_ptr&lt;auto_ptr&lt;T&gt; const&gt;
{ typedef typename auto_ptr&lt;T&gt;::const_auto_ptr_is_not_allowed type; };
</pre>

<p>
There are other techniques to implement this helper class that might work
better for different compliers (i.e. better diagnostics) and therefore I
suggest defining its semantic behavior without mandating any specific
implementation. IMO, and I didn't found any compiler that thinks otherwise,
14.7.1/5 doesn't theoretically defeat the suggested technique but I suggest
verifying this with core language experts.
</p>

<p><b>Further changes in standard text:</b></p>
<p>Remove section 20.4.5.3</p>

<p>Change 20.4.5/2 to read something like:
Initializing <code>auto_ptr&lt;X&gt;</code> from <code>const auto_ptr&lt;Y&gt;</code> will result with unspecified
ill-formed declaration that will require unspecified diagnostic.</p>

<p>Change 20.4.5.1/4,5,6 to read:</p>

<pre>template&lt;class Y&gt; auto_ptr(auto_ptr&lt;Y&gt; const&amp; a) throw();</pre>
<p> 4 <i>Requires</i>: <code>Y*</code> can be implicitly converted to <code>X*</code>.</p>
<p> 5 <i>Effects</i>: Calls <code>const_cast&lt;auto_ptr&lt;Y&gt;&amp;&gt;(a).release()</code>.</p>
<p> 6 <i>Postconditions</i>: <code>*this</code> holds the pointer returned from <code>a.release()</code>.</p>

<p>Change 20.4.5.1/10</p>
<pre>
template&lt;class Y&gt; auto_ptr&amp; operator=(auto_ptr&lt;Y&gt; a) throw();
</pre>
<p>
10 <i>Requires</i>: <code>Y*</code> can be implicitly converted to <code>X*</code>. The expression <code>delete
get()</code> is well formed.
</p>

<p>LWG TC DR #127 is obsolete.</p>

<p>
Notice that the copy constructor and copy assignment operator should remain
as before and accept non-<code>const auto_ptr&amp;</code> since they have effect on the form
of the implicitly declared copy constructor and copy assignment operator of
class that contains auto_ptr as member per 12.8/5,10:
</p>
<pre>
struct X {
    // implicit X(X&amp;)
    // implicit X&amp; operator=(X&amp;)
    auto_ptr&lt;D> aptr_;
};
</pre>

<p>
In most cases this indicates about sloppy programming but preserves the
current <code>auto_ptr</code> behavior.
</p>

<p>
Dave Abrahams encouraged me to suggest fallback implementation in case that
my suggestion that involves removing of <code>auto_ptr_ref</code> will not be accepted.
In this case removing the obsolete conversion member to <code>auto_ptr&lt;Y&gt;</code> and
20.4.5.3/4,5 is still required in order to eliminate ambiguity in legal
cases. The two constructors that I suggested will co exist with the current
members but will make <code>auto_ptr_ref</code> obsolete in initialization contexts.
<code>auto_ptr_ref</code> will be effective in assignment contexts as suggested in DR
#127 and I can't see any serious exception safety issues in those cases
(although it's possible to synthesize such). <code>auto_ptr_ref&lt;X&gt;</code> semantics will
have to be revised to say that it strictly holds pointer of type <code>X</code> and not
reference to an <code>auto_ptr</code> for the favor of cases in which <code>auto_ptr_ref&lt;Y&gt;</code> is
constructed from <code>auto_ptr&lt;X&gt;</code> in which <code>X</code> is different from 
<code>Y</code> (i.e. assignment from r-value derived to base).
</p>

<p><i>[Redmond: punt for the moment. We haven't decided yet whether we
  want to fix auto_ptr for C++-0x, or remove it and replace it with
  move_ptr and unique_ptr.]</i></p>


<p><i>[
Oxford 2007: Recommend NAD.  We're just going to deprecate it.  It still works for simple use cases
and people know how to deal with it.  Going forward <code>unique_ptr</code> is the recommended
tool.
]</i></p>


<p><i>[
2007-11-09: Reopened at the request of David Abrahams, Alisdair Meredith and Gabriel Dos Reis.
]</i></p>


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


<blockquote><p>
This is a complicated issue, so we agreed to defer discussion until
later in the week so that interested parties can read up on it.
</p></blockquote>

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


<blockquote>
<p>
I suggest to close this issue as NAD. The reasons are two-fold: First, the
suggested proposed resolution uses no longer appropriate language means
to solve this issue, which has the effect that the recommended resolution is
another - but better - form of hack. Second, either following the suggested
resolution or the now more natural alternative via the added member set
</p>

<blockquote><pre>
template&lt;class Y&gt; auto_ptr(auto_ptr&lt;Y&gt;&amp;&amp;) throw();
template&lt;class Y&gt; auto_ptr&amp; operator=(auto_ptr&lt;Y&gt;&amp;&amp;) throw();
</pre></blockquote>

<p>
would still have a non-zero probability to break user-code that actively
references <code>auto_ptr_ref</code>. This risk seems to indicate that a
decision which would not touch the current spec of <code>auto_ptr</code> at
all (but deprecating it) and instead recommending to use
<code>unique_ptr</code> for new code instead might have the best
cost-benefit ratio. IMO the current solution of <a href="lwg-defects.html#1100" title="auto_ptr to unique_ptr conversion (Status: Resolved)">1100</a><sup><a href="https://cplusplus.github.io/LWG/issue1100" title="Latest snapshot">(i)</a></sup> can
be considered as an active user-support for this transition.
</p>
</blockquote>

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


<blockquote><p>
Mark as NAD. Alisdair will open a new issue (<a href="lwg-defects.html#1247" title="auto_ptr is overspecified (Status: C++11)">1247</a><sup><a href="https://cplusplus.github.io/LWG/issue1247" title="Latest snapshot">(i)</a></sup>) with
proposed wording to handle <code>auto_ptr_ref</code>.
</p></blockquote>



<p id="res-463"><b>Proposed resolution:</b></p>
<p>
Change the synopsis in 99 [auto.ptr]:
</p>

<blockquote><pre>
namespace std { 
  <del>template &lt;class Y&gt; struct auto_ptr_ref {};</del>

  <ins>// exposition only</ins>
  <ins>template &lt;class T&gt; struct constant_object;</ins>

  <ins>// exposition only</ins>
  <ins>template &lt;class T&gt;</ins>
  <ins>struct cannot_transfer_ownership_from</ins>
    <ins>: constant_object&lt;T&gt; {};</ins>

  template &lt;class X&gt; class auto_ptr { 
  public: 
    typedef X element_type; 

    // D.9.1.1 construct/copy/destroy: 
    explicit auto_ptr(X* p =0) throw(); 
    auto_ptr(auto_ptr&amp;) throw(); 
    template&lt;class Y&gt; auto_ptr(auto_ptr&lt;Y&gt;<ins> const</ins>&amp;) throw(); 
    auto_ptr&amp; operator=(auto_ptr&amp;) throw(); 
    template&lt;class Y&gt; auto_ptr&amp; operator=(auto_ptr&lt;Y&gt;<del>&amp;</del>) throw();
    <del>auto_ptr&amp; operator=(auto_ptr_ref&lt;X&gt; r) throw();</del>
    ~auto_ptr() throw(); 

    // D.9.1.2 members: 
    X&amp; operator*() const throw();
    X* operator-&gt;() const throw();
    X* get() const throw();
    X* release() throw();
    void reset(X* p =0) throw();

    <del>// D.9.1.3 conversions:</del>
    <del>auto_ptr(auto_ptr_ref&lt;X&gt;) throw();</del>
    <del>template&lt;class Y&gt; operator auto_ptr_ref&lt;Y&gt;() throw();</del>
    <del>template&lt;class Y&gt; operator auto_ptr&lt;Y&gt;() throw();</del>

    <ins>// exposition only</ins>
    <ins>template&lt;class U&gt;</ins>
    <ins>auto_ptr(U&amp; rhs, typename cannot_transfer_ownership_from&lt;U&gt;::error = 0);</ins>
  }; 

  template &lt;&gt; class auto_ptr&lt;void&gt; 
  { 
  public: 
    typedef void element_type; 
  }; 

}
</pre></blockquote>

<p>
Remove 99 [auto.ptr.conv].
</p>

<p>
Change 99 [auto.ptr], p3:
</p>

<blockquote><p>
The <code>auto_ptr</code> provides a semantics of strict ownership. An
<code>auto_ptr</code> owns the object it holds a pointer to. Copying an
<code>auto_ptr</code> copies the pointer and transfers ownership to the
destination. If more than one <code>auto_ptr</code> owns the same object at
the same time the behavior of the program is undefined. <ins>Templates
<code>constant_object</code> and <code>cannot_transfer_ownership_from</code>,
and the final constructor of <code>auto_ptr</code> are for exposition only.
For any types <code>X</code> and <code>Y</code>, initializing
<code>auto_ptr&lt;X&gt;</code> from <code>const auto_ptr&lt;Y&gt;</code> is
ill-formed, diagnostic required.</ins> [<i>Note:</i> The uses of
<code>auto_ptr</code> include providing temporary exception-safety for
dynamically allocated memory, passing ownership of dynamically allocated
memory to a function, and returning dynamically allocated memory from a
function. <code>auto_ptr</code> does not meet the <code>CopyConstructible</code>
and <code>Assignable</code> requirements for Standard Library container
elements and thus instantiating a Standard Library container with an
<code>auto_ptr</code> results in undefined behavior. <i>-- end note</i>]
</p></blockquote>

<p>
Change  [auto.ptr.cons], p5:
</p>

<blockquote>
<pre>
template&lt;class Y&gt; auto_ptr(auto_ptr&lt;Y&gt;<ins> const</ins>&amp; a) throw();
</pre>
<blockquote>
<p>
<i>Requires:</i> <code>Y*</code> can be implicitly converted to <code>X*</code>.
</p>
<p>
<i>Effects:</i> Calls <ins><code>const_cast&lt;auto_ptr&lt;Y&gt;&amp;&gt;(</code></ins><code>a</code><ins><code>)</code></ins><code>.release()</code>.
</p>
<p>
<i>Postconditions:</i> <code>*this</code> holds the pointer returned from <code>a.release()</code>.
</p>
</blockquote>
</blockquote>

<p>
Change  [auto.ptr.cons], p10:
</p>

<blockquote>
<pre>
template&lt;class Y&gt; auto_ptr&amp; operator=(auto_ptr&lt;Y&gt;<del>&amp;</del> a) throw();
</pre>
<blockquote>
<p>
<i>Requires:</i> <code>Y*</code> can be implicitly converted to <code>X*</code>.
The expression <code>delete get()</code> is well formed.
</p>
<p>
<i>Effects:</i> Calls <code>reset(a.release())</code>.
</p>
<p>
<i>Returns:</i> <code>*this</code>.
</p>
</blockquote>
</blockquote>






</body>
</html>
