Document number: N4190 Date: 2014-10-09 Project: Programming Language C++, Library Evolution Working Group Reply-to: Stephan T. Lavavej Removing auto_ptr, random_shuffle(), And Old Stuff I. Introduction The C++ Standard is big. We should make it smaller by removing stuff we don't need anymore, like features that have been deprecated for years and thoroughly superseded by more modern machinery. II. What Must Live D.1 "Increment operator with bool operand" [depr.incr.bool] D.2 "register keyword" [depr.register] D.3 "Implicit declaration of copy functions" [depr.impldec] D.4 "Dynamic exception specifications" [depr.except.spec] These Core Language features aren't within the LEWG/LWG's jurisdiction. D.5 "C standard library headers" [depr.c.headers] Why is this even deprecated? D.6 "Old iostreams members" [depr.ios.members] This was deprecated when C++98 shipped, but I don't know how widely this stuff is being used in 2014, or how difficult it would be to change affected code. D.7 "char* streams" [depr.str.strstreams] This was also deprecated when C++98 shipped. The LWG felt that strstreams haven't been superseded with respect to performance, so they can't be removed at this time. D.11 "Violating exception-specifications" [exception.unexpected] These are Library helpers for D.4 [depr.except.spec]'s Core tech. III. What Must Die D.8 "Function objects" [depr.function.objects] This defines unary_function/binary_function, ptr_fun(), and mem_fun()/mem_fun_ref(). unary_function/binary_function were useful helpers when C++98-era adaptors needed argument_type/etc. typedefs. Such typedefs are unnecessary given C++11's perfect forwarding, decltype, and so forth. (And they're inapplicable to overloaded/templated function call operators.) Even if a class wants to provide these typedefs for backwards compatibility, it can do so directly (at a minor cost in verbosity) instead of inheriting from unary_function/binary_function, which is what the Standard itself started doing when these helpers were deprecated. ptr_fun() was necessary when function pointers had to be wrapped in classes before being given to C++98-era adaptors. Again, this is unnecessary in the C++11 world, when function pointers can be given directly to bind(), std::function, and so forth. The only C++98-era adaptors lurking in non-deprecated C++14 are not1()/not2() in 20.9.8 [negators], but (1) lambdas can conveniently negate function calls, and (2) the old negators are being superseded by Library Fundamentals v2's not_fn() in 2.2 [func.not_fn]. mem_fun()/mem_fun_ref() were strictly superseded by mem_fn(). D.9 "Binders" [depr.lib.binders] This defines bind1st()/bind2nd(), which were strictly superseded by bind(). (In the future, I'll argue that bind() itself has been superseded by lambdas and especially generic lambdas, so bind() should be deprecated, but that isn't part of this proposal.) D.10 "auto_ptr" [depr.auto.ptr] auto_ptr has been superseded by unique_ptr. Any code using auto_ptr can be mechanically converted to using unique_ptr, with move() inserted whenever auto_ptr was being "copied". clang-modernize's Replace-AutoPtr Transform does exactly this (see [1]). D.12 "Random shuffle" [depr.alg.random.shuffle] This defines random_shuffle(first, last) and random_shuffle(first, last, rng). (The latter takes a RandomNumberGenerator, whose requirements are totally different from C++11's UniformRandomNumberGenerator.) The problem with random_shuffle(first, last) is that it's permitted to use rand(), which is permitted to be low quality. (rand() is even permitted to introduce data races, 26.8 [c.math]/5, although I'm not aware of any implementation that does so.) Constructing mt19937 urng and calling shuffle(first, last, urng) is a far superior alternative. Unlike random_shuffle(first, last), calling shuffle(first, last, urng) requires the user to be aware of the URNG's existence and state, but I argue that this is a feature, not a bug. random_shuffle(first, last, rng) is the Knuth shuffle algorithm. It's not evil, but it's almost unusable in practice, because the "rng" function object is required to provide a very strange interface. (It's actually required to return a uniform integer distribution over a varying interval, which is difficult to do without introducing bias.) shuffle(first, last, urng) is vastly easier to use, because it directly consumes a URNG. IV. Questions And Answers Q1. Is this stuff really icky and bad and yucky? A1. Yes. Remember that we've already made the difficult decisions to deprecate this stuff. Now we're faced with the easier task of simply verifying that each deprecated component really has been superseded by future technology. Q2. Will removing this stuff from the Standard immediately break the world? A2. No. Remember that the Standard is not an implementation. An implementation is free to provide a strictly conforming C++14 mode with all of this deprecated stuff, and a strictly conforming C++17 mode without any of this stuff. Also, an implementation can provide a C++17 mode with the very slightly nonconformant behavior of also implementing this stuff according to C++14's specification. It would be nonconforming in the sense that if C++17 doesn't mention auto_ptr, then "using namespace std;" shouldn't drag in such a name, and users should be free to macroize auto_ptr. In practice, we all know that such a hybrid mode wouldn't be problematic. Practically speaking, implementations will be able to migrate away from deprecated-then-removed stuff as quickly or as slowly as they like. Because none of this machinery depends on "magic" (unlike unexpected(), for example), a third party can provide it even if a Standard Library vendor chooses not to. (The only exception is auto_ptr's integration with unique_ptr/shared_ptr.) Q3. Then why bother removing anything? A3. Removing this stuff from the Standard will reduce the editors and LWG's burdens - slightly, but nonzero. More significantly, it sends a very clear message to authors, teachers, and the C++ community that this stuff shouldn't be used anymore. Finally, it allows implementers to discard their implementations, if they wish to be aggressive about migration. V. Standardese 1. In 20.7.2 "Header synopsis" [memory.syn], remove: // D.10, auto_ptr (deprecated) template class auto_ptr; 2. In 20.8.1.2 [unique.ptr.single], remove: template unique_ptr(auto_ptr&& u) noexcept; 3. Remove 20.8.1.2.1 [unique.ptr.single.ctor]/22-24: template unique_ptr(auto_ptr&& u) noexcept; Effects: Constructs a unique_ptr object, initializing the stored pointer with u.release() and value-initializing the stored deleter. Postconditions: get() yields the value u.get() yielded before the construction. u.get() == nullptr. get_deleter() returns a reference to the stored deleter. 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. 4. In 20.8.2.2 [util.smartptr.shared], remove: template shared_ptr(auto_ptr&& r); 5. In 20.8.2.2 [util.smartptr.shared], remove: template shared_ptr& operator=(auto_ptr&& r); 6. Remove 20.8.2.2.1 [util.smartptr.shared.const]/28-32: template shared_ptr(auto_ptr&& r); 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. Effects: Constructs a shared_ptr object that stores and owns r.release(). Postconditions: use_count() == 1 && r.get() == 0. Throws: bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained. Exception safety: If an exception is thrown, the constructor has no effect. 7. In 20.8.2.2.3 [util.smartptr.shared.assign], remove: template shared_ptr& operator=(auto_ptr&& r); 8. In 20.9 [function.objects]/2 "Header synopsis", remove: // D.8.1, base (deprecated): template struct unary_function; template struct binary_function; 9. In 20.9 [function.objects]/2 "Header synopsis", remove: // D.9, binders (deprecated): template class binder1st; template binder1st bind1st(const Fn&, const T&); template class binder2nd; template binder2nd bind2nd(const Fn&, const T&); // D.8.2.1, adaptors (deprecated): template class pointer_to_unary_function; template pointer_to_unary_function ptr_fun(Result (*)(Arg)); template class pointer_to_binary_function; template pointer_to_binary_function ptr_fun(Result (*)(Arg1,Arg2)); // D.8.2.2, adaptors (deprecated): template class mem_fun_t; template class mem_fun1_t; template mem_fun_t mem_fun(S (T::*f)()); template mem_fun1_t mem_fun(S (T::*f)(A)); template class mem_fun_ref_t; template class mem_fun1_ref_t; template mem_fun_ref_t mem_fun_ref(S (T::*f)()); template mem_fun1_ref_t mem_fun_ref(S (T::*f)(A)); template class const_mem_fun_t; template class const_mem_fun1_t; template const_mem_fun_t mem_fun(S (T::*f)() const); template const_mem_fun1_t mem_fun(S (T::*f)(A) const); template class const_mem_fun_ref_t; template class const_mem_fun1_ref_t; template const_mem_fun_ref_t mem_fun_ref(S (T::*f)() const); template const_mem_fun1_ref_t mem_fun_ref(S (T::*f)(A) const); 10. In 25.1 [algorithms.general] "Header synopsis", remove: // D.12, random_shuffle (deprecated): template void random_shuffle(RandomAccessIterator first, RandomAccessIterator last); template void random_shuffle(RandomAccessIterator first, RandomAccessIterator last, RandomNumberGenerator&& rng); 11. After C.3 [diff.cpp11], add a new section: C++ and ISO C++ 2014 [diff.cpp14] This subclause lists the differences between C++ and ISO C++ 2014 (ISO/IEC 14882:2014, Programming Languages - C++), by the chapters of this document. 12. As a child of [diff.cpp14], add a new section: Annex D: compatibility features [diff.cpp14.depr] Change: The class templates auto_ptr, unary_function, and binary_function, the function templates random_shuffle, and the function templates (and their return types) ptr_fun, mem_fun, mem_fun_ref, bind1st, and bind2nd are not defined. Rationale: Superseded by new features. Effect on original feature: Valid C++ 2014 code that uses these class templates and function templates may fail to compile in this International Standard. 13. Remove the section D.8 [depr.function.objects]. 14. Remove the section D.9 [depr.lib.binders]. 15. Remove the section D.10 [depr.auto.ptr]. 16. Remove the section D.12 [depr.alg.random.shuffle]. VI. Acknowledgements Thanks to Billy O'Neal and Giovanni Dicanio for reviewing this proposal. VII. References All of the Standardese citations in this proposal are to Working Paper N3936: http://www.open-std.org/jtc1/sc22/wg21/prot/14882fdis/n3936.pdf All of the Library Fundamentals v2 citations in this proposal are to Working Draft N4084: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4084.html [1] clang-modernize documentation, Replace-AutoPtr Transform: http://clang.llvm.org/extra/ReplaceAutoPtrTransform.html (end)