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 使其成为可能,从而导致未定义的行为,通常会产生数据竞争。

要处理弃用,必须执行两个步骤:

或者,也可以直接使用 std::atomic 成员函数,而不是使用 std::shared_ptr 重载。有关更多详细信息,请查看 P2869R4 中的 5.1 节。

移除 std::wstring_convert

std::wstring_convertstd::wbuffer_convert 和一些相关的辅助函数由 C++11 引入,被 C++17 弃用,最终被 C++26 通过 P2872R3 移除。你用过它吗?我以前没听说过。

它们有助于在普通大小和宽字符串之间进行转换。

移除它们的原因是它们规范不明确,存在一些与它们相关的未解决的 LWG 问题,并且改进这些设施_“需要比委员会希望投入的更多的工作,才能将其提升到所需的水平”_。

弃用 std::is_trivialstd::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 中取消弃用的特性。敬请期待。