ISO/IEC JTC1 SC22 WG21
N4168
Billy Baker
2014-10-02
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.
The conclusion of N1856 for deprecating auto_ptr
was:
Conclusion:N1856 also pointed out that one feature of
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.
auto_ptr
was no longer valid.
In the 7 years since the adoption of N1856, the material for learning C++ has made it clear thatauto_ptr
was originally intended to allow for easy conversions between base and derived types. However recent changes to the standard result inauto_ptr<Base>
not cooperating as originally intended withauto_ptr<Dervied>
:
struct B {virtual ~B() {}}; struct D : B {}; auto_ptrap_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 }
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?"
- At the time of its design, the language had no move semantics for constructors and assignment operators. However, the goal was still to provide the semantics of ownership transfer. As a result, copy and assignment operators got a move semantic, which could cause serious trouble, especially when passing an
auto_ptr
as argument- There was no semantic of a deleter, so you could use it only to deal with single objects allocated with new.
- Because this was initially the only smart pointer provided by the C++ standard library, it was often misused, especially assuming that it provided the semantics of shared ownership as class
shared_ptr
does now.
While simple find and replace would work, tools have also been developed to modernize C++ code using transformations such as replacingauto_ptr
is most charitably characterized as a valiant attempt to create aunique_ptr
before C++ had move semantics.auto_ptr
is now deprecated, and should not be used in new code.
If you haveauto_ptr
in an existing code base, when you get a chance try doing a global search-and-replace ofauto_ptr
tounique_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.
auto_ptr
with unique_ptr
.
These proprosed changes are relative to N3797
Change in 20.7.2 (memory.syn):
// D.10, auto_ptr (deprecated) templateclass 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).
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.