Chapter35 废弃和移除的特性

C++17中又有一些特性被废弃或者彻底被移除。

实现可能仍然提供被移除的特性,但你不应该依赖它。 如果你使用了这些废弃的特性实现应该可能会给出一个警告。

35.1 废弃和移除的核心语言特性

35.1.1 throw声明

动态异常声明不再受支持(它们自从C++11起就已经被废弃):

  1. void f6() throw(std::bad_alloc); // ERROR:自从C++17起无效

空异常声明仍然可以使用但仍然被废弃:

  1. void f5() throw(); // 自从C++11起废弃

使用noexcept作为替代(它现在已经是函数类型的一部分):

  1. void f5() noexcept; // OK

35.1.2 关键字register

关键字register不再有任何标准化的语义,但仍然保留:

  1. register int x = 42; // 自从C++17起ERROR
  2. std::string register; // 在所有版本的C++中仍然ERROR

register仍然保留的一个原因是它仍然是C里有标准化语义的关键字 (例如,它可以出现在函数的参数列表中)。

因为这个关键字已经在C++11和C++14中被废弃,如果因为使用了register而编译失败, 只需要移除这个关键字即可。

35.1.3 禁止bool类型的++

你不能再对bool类型的对象调用++(调用--从来都不允许):

  1. bool b{false};
  2. ++b; // 自从C++17起ERROR

作为代替,使用:

  1. b = true;

35.1.4 三字符

你不能再使用代表特殊字符的三字符序列(例如??=代表#)。

一开始引入这个特性是为了一些没有像#这样的特殊字符的打字机准备的。 现在已经没有必要再支持这个特性。

35.1.5 static constexpr成员的定义/重复声明

因为static constexpr数据成员现在隐式inline, 所以稍后的定义不再是必须的,并会被认为是多余的重复声明。 因此,这样的定义/重新声明现在已经被废弃:

  1. struct D {
  2. static constexpr int n = 5; // 以前是声明,现在是定义
  3. };
  4. constexpr int D::n; // 以前是定义,现在被废弃

35.2 废弃和移除的库特性

35.2.1 auto_ptr

智能指针std::auto_ptr<>终于被移除。它在C++98中标准化,它会尝试使用拷贝操作 提供独占式的所有权移动语义,这可能会导致一些错误或者副作用。

使用std::unique_ptr<>代替它。

35.2.2 算法random_shuffle()

C++98中提供的随机重排元素顺序的random_shuffle()算法终于被移除。

使用std::shuffle()代替它,或者如果你需要集合的随机子集, 请使用新算法std::sample()

35.2.3 unary_functionbinary_function

实现函数对象的辅助函数std::unary_functionstd::binary_function终 于被移除。当定义函数对象时它们用来为类型定义提供一种简单的标准化的方法。 然而,有了C++11的新语言特性(lambda、decltype、…) 它们不再是必须的,也不再适用于任何场景。

移除基类并手动提供必须的类型定义来替代它们。

35.2.4 ptr_fun()mem_fun()、绑定器

绑定器和用于创建更加复杂的函数调用适配器的包装终于被移除:

  • 为了代替std::ptr_fun(),你现在可以使用lambda,类模板std::function<>、 函数模板std::bind()
  • 为了代替std::mem_fun()std::mem_fun_ref(),你现在可以 使用lambda和std::mem_fn()
  • 为了代替std::bind1st()std::bind2nd(),你现在可以 使用lambda和函数模板std::bind()

35.2.5 std::function<>的分配器支持

一开始类模板std::function<>被标准化时是有分配器支持的。 然而,没有主流编译器完全实现了这个支持,并且这个规则导致了一些有趣的问题 (见library issues 2385, 2386, 2062, 2370, 2501, 2502)。

最终,在C++17中移除了std::function<>的分配器支持。

35.2.6 废弃的IO流别名

自从C++98就已经废弃的IO流的类型和函数别名终于被移除:

  • std::ios_base中的io_state类型
  • std::ios_base中的open_mode类型
  • std::ios_base中的seek_dir类型
  • std::ios_base中的streamoff类型
  • std::ios_base中的streampos类型
  • std::basic_streambuf<>中的stossc()
  • std::basic_ios<>中的clear(io_state)
  • std::basic_ios<>中的setstate(io_state)
  • std::basic_ios<>中的exceptions(io_state)
  • std::basic_streambuf<>中的pubseekoff(off_type, ios_base::seek_dir, ios_base::open_mode)
  • std::basic_streambuf<>中的pubseekpos(pos_type, ios_base::open_mode)
  • std::basic_filebuf<>std::basic_ifstream<>std::basic_ofstream<>中 的 open(const char*, ios_base::open_mode)

35.2.7 废弃的库特性

下列的库特性自从C++17起被废弃,不应该再使用:

  • 类型特征result_of<>被废弃。

    使用invoke_result<>代替它。

  • 类型特征is_literal_type<>被废弃。

  • 对于智能指针,成员函数unique()被废弃。

    使用use_count()代替它。

  • 对字符编码转换的支持(头文件<codecvt>和标准类wstring_convert<>wbuffer_convert<>)被废弃。

    这个功能在C++11中引入,但在实践中发现这个方法并不是很有用并且还有一些安全漏洞。 为了给C++20中提供的更好的字符编码支持腾出空间,<codecvt>中的所有内容和用于 字符转换的类在C++17中都被废弃。

  • std::iterator<>被废弃。

  • std::raw_storage_iterator<>被废弃。
  • std::get_temporary_buffer()被废弃。
  • void特化的标准分配器std::allocator<void>被废弃。
  • 头文件<ccomplex><cstdalign><cstdbool><ctgmath>的使用被废弃。
  • std::uncaught_exception()的使用被废弃。

    使用std::uncaught_exceptions()代替它。

  • 内存同步顺序memory_order_consume暂时不鼓励使用。 它现在不是很有用,不过之后或许会修复它。

    当前阶段,使用memory_order_acquire代替它。