C++17 removed and deprecated features

Along with the new features added to the language and the standard library in C++17, there are also existing features that have been either removed (after being deprecated in a previous version) or deprecated so they would be removed sometime in the future. Although not complete, the following tables list the most important of these removed or deprecated features.

The following table lists features that were removed in C++17.

Feature Comments Alternatives
throw(typeid) Explicit dynamic specification allowed specifying one or more types for exception that might be thrown by a function. This feature does not have an alternative. Instead, functions should only specify whether they could throw exceptions or not (without specifying their type). noexcept is the specifier use for this purpose. However, make sure you use it only when it’s guarantee that the invocation of the function cannot throw any error; otherwise, the program will terminate abnormally with a call to std::terminate().
operator++ for bool The pre-fix and post-fix operator++ was overloaded for type bool. In both cases, the return value for a bool argument is true. Since the bool type does not support the full set of arithmetic types, it is no longer considered an arithmetic type and these operators have been removed. std::exchange for the rare cases where the post-fix operator has valid uses. See exchange() utility function, revision 3 for examples of these cases.
Trigraphs Trigraphs (short for three-character groups) are alternatives for some characters, introduced with two question marks (which is also the reason the question mark has to be escaped '\?'). They were introduced for compatibility with C which had them for keyboards that did not support the ISO 646 character set. Trigraphs are parsed before comments and string literals are recognized and can be a source of confusion for many programmers. For reason of deprecation see Comment on proposed trigraph deprecation. None
register storage specifier Was a specifier for objects declared at block scope or in function parameter lists to indicate automatic storage duration as well as a hint to the compiler that these variables might be heavily used so that it can do optimization by storing it in a CPU register. Since the automatic storage duration for these kinds of variables is implicit and the hint was rarely used by the compilers this feature was deprecated in C++11 and removed in C++17. None
std::auto_ptr auto_ptr was the attempt to create a smart pointer to handle an object’s lifetime before move semantics were available. This smart pointer quietly steals ownership of the managed object in its copy constructor and copy assignment from the right-hand argument. As a result, the copy is not the same as the original smart pointer object. Because of these copy semantics, auto_ptr does not meet the requirements of being CopyConstructible, and therefore cannot be used in standard containers. For more information about the deprecation of auto_ptr see N1856. For most uses, std::unique_ptr is the direct replacement of std::auto_ptr. In many cases, it can be a simple drop in replacement, although an explicit move might be necessary to be done. For more information on the topic see this discussion.
std::random_shuffle This algorithm reorders elements of a range so that each possible permutation of its elements has an equal probability of appearance. The problem with it is that it may depend on the rand family of C functions, that may be deprecated in the future. On the other hand, it may also have global state for seeding and others. For more information see std::random_shuffle is deprecated in C++14. The replacement is std::shuffle, that needs as the third argument a uniform random bit generator. Although the replacement of the algorithm itself is trivial, you need to setup a URNG, several standard ones being available in the <random> header.
std::unary_function, std::binary_function These are former types used solely for defining some types (argument and result types). They used to be the base class for function objects that required these type definitions because they were necessary in some parts of the standard library. Such an function object was std::less. These restrictions have been lifted in C++11 because they were actually an overspecification. If needed, define the argument and result types in your class.
std::pointer_to_unary_function, std::pointer_to_binary_function Function objects that act as wrappers around unary or binary functions. std::function and std::ref
std::ptr_fun Creates instances of std::pointer_to_unary_function and std::pointer_to_binary_function.
std::mem_fun_t,
std::mem_fun1_t,
std::const_mem_fun_t,
std::const_mem_fun1_t,
std::mem_fun_ref_t,
std::mem_fun1_ref_t,
std::const_mem_fun_ref_t,
std::const_mem_fun1_ref_t
These are function objects that wrap a pointer to a member function with no parameters or one parameter. For the former, the object whose member function to call is passed by pointer to the call operator; for the latter, it is passed as a reference. They are deprecated because they are limited to member functions with either none or just one argument and you need different functions and function objects for handling pointers or references to the class instance. std::mem_fn is a variadic template that can handle member functions with any number of variables and not only references or pointers to objects but also smart pointers.
std::mem_fun, std::mem_fun_ref These are helper functions that create the member function wrapper objects above.
std::binder1st, std::binder2nd These are function objects that bind an argument to a binary function. Lambdas, std::bind
std::bind1st, std::bind2nd Helper functions that create instances of std::binder1st or std::binder2nd, binding a given argument to a first or second parameter of a given binary function object.
These were remnants of utility functions in STL that did make it into C++98 but became obsolete with the introduction of lambdas in C++11, when they were deprecated.
std::function allocator support Several constructors allow to specify an allocator used for allocating internal memory if needed. However, this was later considered poorly specified and inconsistently implemented (with some implementation not providing these overloads at all). Therefore, these constructor overloads were removed in C++17. None
std::uses_allocator<std::function> A specialization of std::uses_allocator used for indicating that all objects of type std::function support uses-allocator construction. This was removed together with the allocator support for std::function.

The following table lists features that were deprecated in C++17 and removed in C++20.

Feature Comments Alternatives
std::uncaught_exception This function indicates whether the stack unwiding is already in progress. It assumes there’s only one active exception in a thread, although multiple can exist simultaneously. This function was sometimes wrongly used in destructors to detect if the destructor was called due to stack unwiding. But as explained in GotW #47: Uncaught Exceptions, that is a bad pattern, because once unwinding of any exception, everything looks like unwiding regardless how many active exception exist. As a result, this function had no useful purpose and will be removed. For more information see N4152. std::uncaught_exceptions indicates the number of exceptions in the current thread that have been thrown/rethrown and not yet entered their matching catch clauses.
throw() This is the non-throwing version of the dynamic exception specification hat has been deprecated and now removed. This specifier has been replaced with noexcept a term that is more clear on its intent. noexcept
std::unary_negate, std::binary_negate These are wrapper function objects that return the complement of the unary or binary predicate they hold. Lambdas, std::not_fn
std::not1, std::not2 These are helper functions used to construct std::unary_negate and std::binary_negate function objects.
std::get_temporary_buffer, std::return_temporary_buffer, std::raw_storage_iterator These are remnants of the original STL implementation that where added into the standard together with other utilities but have little to no real usefulness nowadays (although they’re used internally by some standard algorithms like stable_partition()) and therefore have been deprecated and will be removed. See Why do I need std::get_temporary_buffer? for more information on the utility of these functions. None
std::is_literal_type, std::is_literal_type_v The intention of this type trait was to ensure that a specific construction would produce constant initialization. However, the requirement that a type should have at least one constexpr constructor (that is not a copy or move constructor) it too week to ensure such guarantee. See Deprecate the is_literal Trait for the rational of deprecating this feature. None
std::result_of, std::result_of_t This is a type trait used to deduce the return type of an invoke expression at compile time. In C++11, its behaviour is undefine when the invoke expression is ill-formed (if F is not a callable type, reference to function, or reference to callable type). In C++14, this was changed to SFINAE. Because of its limitations (for instance F cannot be a function type, but can be a reference to it, and F and any of its arguments cannot be an abstract class type, etc.) it has been replaced with std::invoke_result. std::invoke_result
std::shared_ptr::unique Indicates whether the current object is the only shared_ptr instance that manages the object. This function does not work properly in a multithreading environement, the use count of the object being only an approximation. This was initially intended as a debug only feature but to work properly it needs synchronization, which is not used in practice. See Why is std::shared_ptr::unique() deprecated? for more information. None

The following table lists features that were deprecated in C++17.

Feature Comments Alternatives
<codecvt> header Is a part of the localization library, providing facets for converting between byte and wide character sets (such as UTF-8 and UTF-16). It was deprecated because it is not considered “the best way to address transcoding”, for several reasons, such as lacking of default error handling mechanisms for attacks through ill-formed UTF, obscure specifications, lack of portability, etc. For more information, see Deprecating <codecvt>. None
std::wbuffer_convert, std::wstring_convert These are utility types that perform conversion between a byte stream buffer and a wide stream buffer and, respectively, between a byte string and a wide string using conversion facets from <codecvt> (the ones available are std::codecvt_utf8 for UTF-8/UCS2 and UTF-8/UCS4 conversions and std::codecvt_utf8_utf16 for UTF-8/UTF-16 conversions). Since these go together with the deprecated standard facets from <codecvt>, they have been also deprecated. None
std::iterator Is a base class that was provided in the first version of the standard to simplify the definition of iterator types by providing five type definitions (iterator_category, value_type, difference_type, pointer, reference). It is often used with a sequence of void arguments (such as in iterator<output_iterator_tag, void, void, void, void>). Following the pattern with deprecating unary_function and binary_function and explicitly definiting the types in the class rather than having a base class for that, the iterator class has also been deprecated. Specify the necessary type definitions in your class.

For more changes between C++14 and C++17 see this document.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.