C++26:弃用或移除的库特性
C++26:弃用或移除的库特性
Sandor Dargo 1 天前 2025-03-19T00:00:00+01:00 5 分钟
在之前的文章中,我们讨论了C++26 中移除了哪些语言特性。在这篇文章中,我们将介绍在弃用几年后最终被移除的语言特性,以及那些将被 C++26 弃用的特性。
提醒一下,从语言中移除通常分两步进行。首先,一个特性被弃用,这意味着用户在使用被弃用的特性时会收到编译器警告。下一步,在某些情况下可能永远不会发生,就是最终移除编译器支持。
从 C++26 中移除已弃用的 std::allocator
Typedef
std::allocator
有一个 typedef
,它在 C++20 中被弃用,现在终于被移除了。虽然这是一个很小的边缘情况,但它太容易被误用,以至于委员会都觉得尴尬,因此通过 P2868R3 移除了它。
从 std::allocator
派生的类不能正确地合成 typedef
成员,分配器作者必须添加自己的 typedef
以确保正确的行为。如果他们知道的话...
移除 std::basic_string::reserve()
的无参数函数重载
我刚刚从 P2870R3 中了解到,std::basic_string::reserve
有一个不带参数的重载。由于它是 std::basic_string::shrink_to_fit
的一个糟糕的替代品,它在 C++20 中被弃用。
现在它消失了。
reserve
过去对其唯一的参数有一个默认值 0
,使其成为一个非强制性的 shrink_to_fit
。但是 shrink_to_fit
在 C++11 中被引入作为一个独立的函数,因此 reserve
的这种行为变得多余,并在“几年”后被弃用。
如果你的代码使用了不带任何参数的 reserve()
,迁移很简单,只需将其替换为 shrink_to_fit
。
从 C++26 中移除已弃用的 Unicode 转换 Facet
<codecvt>
头文件最初由 C++11 提供,然后由于其规范不明确(特别是缺乏错误处理)而被 C++17 弃用。它在 C++26 中通过 P2871R3 移除。
该库包含几个辅助类,用于在不同的 UTF 格式之间进行转换。由于规范不明确,格式错误的 UTF 字符串可能被用作攻击媒介。
此更改旨在提高语言安全性。
Freestanding:移除 std::strtok
std::strtok
一直是 C++ freestanding 的一部分,换句话说,它是一个 C 函数,是 C++ 的一部分,以帮助兼容性。由于 std::strtok
已从 C2X 标准中移除,C++ 也不再需要它。
“一个 freestanding C++ 实现主要是 freestanding C 实现的超集,即使在 C++ 的“C”部分也是如此。这意味着 freestanding C++ 实现通常不能建立在最小的 freestanding C 实现之上。要么 C++ 实现必须提供一些 C 部分,要么 C++ 实现将需要一个提供比最小值更多的 C 实现。” - source
移除已弃用的 strstreams
C++20 引入了有效地将字符串从 stringstreams 中移出的能力,C++23 为我们带来了 spanstream
库,我们已经在 C++23: The rise of new streams 中介绍过。
鉴于 C++ 现在有了 char*
流的更好替代品,它们现在终于被移除了。
为什么是终于?
嗯,显然,char*
流是标准中最大和最古老的已弃用特性。它们在近 30 年前就被标记为未来弃用和可能移除!是的,我们说的是 C++98。
我们需要取消弃用这些特性吗?
希望不会。
移除已弃用的 std::shared_ptr
原子访问 API
C++11 引入了 atomics 和智能指针。其中,它还引入了一个用于原子访问 shared_ptr
的自由函数 API。这是一个易于使用的 API,因此它被 C++20 弃用,同时引入了类型安全的替代品 std::atomic<shared_ptr<T>>
。由于接受了 P2869R4,C++26 移除了已弃用的 API。
虽然旧的 API 期望共享对象不被直接使用,但该 API 使其成为可能,从而导致未定义的行为,通常会产生数据竞争。
要处理弃用,必须执行两个步骤:
- 包含
<atomic>
头文件 - 将
shared_ptr<T>
替换为std::atomic<shared_ptr<T>>
或者,也可以直接使用 std::atomic
成员函数,而不是使用 std::shared_ptr
重载。有关更多详细信息,请查看 P2869R4 中的 5.1 节。
移除 std::wstring_convert
std::wstring_convert
、std::wbuffer_convert
和一些相关的辅助函数由 C++11 引入,被 C++17 弃用,最终被 C++26 通过 P2872R3 移除。你用过它吗?我以前没听说过。
它们有助于在普通大小和宽字符串之间进行转换。
移除它们的原因是它们规范不明确,存在一些与它们相关的未解决的 LWG 问题,并且改进这些设施_“需要比委员会希望投入的更多的工作,才能将其提升到所需的水平”_。
弃用 std::is_trivial
和 std::is_trivial_v
当我看到这个被接受的提案时,我很惊讶。移除 std::is_trivial
?难道人们没有经常谈论 trivial 类吗?但这只是我浅薄知识的标志。
事实是,人们不谈论 trivial 类——这个概念也被弃用了。人们谈论的是 trivially default constructible、trivially copyable 或 trivially copy assignable 类。通常,这些属性不是同时需要的。
此外,is_trivial
甚至不检查所需的构造函数是否是 public 的。
使用适当的 is_trivially_XXX
检查,而不是通用的 is_trivial
,特别是现在后者已被 P3247R2 弃用。
削弱并弃用 std::memory_order::consume
std::memory_oder::consume
的问题已经存在了十年。它的规范不令人满意,难以实现,甚至不是大多数广泛使用的 CPU 架构所要求的。鉴于这些问题,大多数学术工作只是忽略了它的存在,并使用其他内存模型。
但即使是实现也大多将其映射到 std::memory_oder::acquire
。由于没有改进它的意愿和共识,最好的下一步就是弃用它,P3475R1 提案正是如此。
结论
在上周讨论了从 C++26 中移除的语言特性之后,本周我们介绍了哪些库特性被移除或通过弃用开始了移除之路。
弃用并不总是一条单行道。下周,我们将介绍一个将在 C++26 中取消弃用的特性。敬请期待。