ISO/IEC JTC1 SC22 WG21
N4168
Billy Baker
2014-10-02

Removing auto_ptr

Introduction

At Oxford in 2007, N1856 was accepted adding unique_ptr and making auto_ptr deprecated. At CppCon in 2014, Howard Hinnant stated that he would like to see auto_ptr removed from future C++ standards. This paper proposes that auto_ptr be removed entirely. Removing auto_ptr now would give plenty of time before the next C++ standard for code to be updated if necessary.

Proposal

The conclusion of N1856 for deprecating auto_ptr was:

Conclusion:
One should not move from lvalues using copy syntax. Other syntax for moving should be used instead. Otherwise generic code is likely to initiate a move when a copy was intended.

auto_ptr moves from lvalues using copy syntax and is thus fundamentally unsafe.
N1856 also pointed out that one feature of auto_ptr was no longer valid.
auto_ptr was originally intended to allow for easy conversions between base and derived types. However recent changes to the standard result in auto_ptr<Base> not cooperating as originally intended with auto_ptr<Dervied>:

    struct B {virtual ~B() {}};
    struct D : B {};

    auto_ptr
    ap_factory()
    {
        return auto_ptr();
    }

    void ap_sink(auto_ptr<B>);

    void test()
    {
        auto_ptr<B> ap = ap_factory();  // error:
                                        // no suitable copy constructor
        ap_sink(ap_factory());   // error: no suitable copy constructor
    }
In the 7 years since the adoption of N1856, the material for learning C++ has made it clear that auto_ptr should not be used. In The C++ Standard Library Second Edition, Nico Josuttis lists problems with auto_ptr.
Herb Sutter's GotW #89 on Smart Pointers answers the question of "What's the deal with auto_ptr?"
auto_ptr is most charitably characterized as a valiant attempt to create a unique_ptr before C++ had move semantics. auto_ptr is now deprecated, and should not be used in new code.

If you have auto_ptr in an existing code base, when you get a chance try doing a global search-and-replace of auto_ptr to unique_ptr; the vast majority of uses will work the same, and it might expose (as a compile-time error) or fix (silently) a bug or two you didn’t know you had.
While simple find and replace would work, tools have also been developed to modernize C++ code using transformations such as replacing auto_ptr with unique_ptr.

Proposed wording

These proprosed changes are relative to N3797

Change in 20.7.2 (memory.syn):

// D.10, auto_ptr (deprecated)
template  class auto_ptr;

Change 20.8.1.2 (unique.ptr.single):

// 20.8.1.2.1, constructors
constexpr unique_ptr() noexcept;
explicit unique_ptr(pointer p) noexcept;
unique_ptr(pointer p, see below d1) noexcept;
unique_ptr(pointer p, see below d2) noexcept;
unique_ptr(unique_ptr&& u) noexcept;
constexpr unique_ptr(nullptr_t) noexcept
  : unique_ptr() { }
template <class U, class E>
  unique_ptr(unique_ptr<U, E>&& u) noexcept;
template <class U>
  unique_ptr(auto_ptr<U>&& u) noexcept;

Change 20.8.1.2.1 (unique_ptr.single.ctor) to delete paragraphs 22 through 24.

template <class U>	
unique_ptr(auto_ptr<U>&& u) noexcept;
-22- Effects: Constructs a unique_ptr object, initializing the stored pointer with u.release() and valueinitializing the stored deleter. -23- Postconditions: get() yields the value u.get() yielded before the construction. u.get() == nullptr. get_deleter() returns a reference to the stored deleter. -24- Remarks: This constructor shall not participate in overload resolution unless U* is implicitly convertible to T* and D is the same type as default_delete<T>.

Change in 20.8.2.2 (util.smartptr.shared):

// 20.8.2.2.1, constructors:
constexpr shared_ptr() noexcept;
template<class Y> explicit shared_ptr(Y* p);
template<class Y, class D> shared_ptr(Y* p, D d);
template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template <class D> shared_ptr(nullptr_t p, D d);
template <class D, class A> shared_ptr(nullptr_t p, D d, A a);
template<class Y> shared_ptr(const shared_ptr<Y>& r, T* p) noexcept;
shared_ptr(const shared_ptr& r) noexcept;
template<class Y> shared_ptr(const shared_ptr<Y>& r) noexcept;
shared_ptr(shared_ptr&& r) noexcept;
template<class Y> shared_ptr(shared_ptr<Y>&& r) noexcept;
template<class Y> explicit shared_ptr(const weak_ptr<Y>& r);
template<class Y> shared_ptr(auto_ptr<Y>&& r);
template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);
constexpr shared_ptr(nullptr_t) : shared_ptr() { }
// 20.8.2.2.2, destructor: ~shared_ptr();
// 20.8.2.2.3, assignment: shared_ptr& operator=(const shared_ptr& r) noexcept; template<class Y> shared_ptr& operator=(const shared_ptr<Y>& r) noexcept;
shared_ptr& operator=(shared_ptr&& r) noexcept; template<class Y> shared_ptr& operator=(shared_ptr<Y>&& r) noexcept; template<class Y> shared_ptr& operator=(auto_ptr<Y>&& r); template <class Y, class D> shared_ptr& operator=(unique_ptr<Y, D>&& r);

Change 20.8.2.2.1 (util.smartptr.shared.const) to remove paragraphs 28 through 32:

template<class Y> shared_ptr(auto_ptr<Y>&& r);
-28- Requires: r.release() shall be convertible to T*. Y shall be a complete type. The expression delete r.release() shall be well formed, shall have well defined behavior, and shall not throw exceptions. -29- Effects: Constructs a shared_ptr object that stores and owns r.release(). -30- Postconditions: use_count() == 1 && r.get() == 0. -31- Throws: bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained. -32- Exception safety: If an exception is thrown, the constructor has no effect.

Change 20.8.2.2.3 (util.smartptr.shared.assign):

shared_ptr& operator=(const shared_ptr& r) noexcept;
template<class Y> shared_ptr& operator=(const shared_ptr<Y>& r) noexcept;
template<class Y> shared_ptr& operator=(auto_ptr<Y>&& r);
-1- Effects: Equivalent to shared_ptr(r).swap(*this).
-2- Returns: *this.

Remove D.10 (depr.auto.ptr).

LWG Issues Impact

2118. [CD] unique_ptr for array does not support cv qualification conversion of actual argument

Issue 2118 has a current status of Review. The original wording to resolve 2118 involved additional usage of auto_ptr. This wording has been superseded by N4089 which does not reference auto_ptr. The proposed wording changes from this proposal should not impact N4089.

2399. shared_ptr's constructor from unique_ptr should be constrained

Issue 2399 has a current status of Ready. Stephan noted that this issue would affect the shared_ptr constructor from auto_ptr. With the proposed changes, the noted issue with the shared_ptr constructor from auto_ptr would no longer be valid. The current wording to resolve 2399 should not be impacted.

Acknowledgements

Thanks to Howard Hinnant for the inspiration and for reviewing an early draft.