const_cast:必要之恶
摘要
本文解释了为什么在C++中有时必须使用const_cast,特别是从std::priority_queue中移动对象时,以及如何安全地使用它。
<p><a href="https://lobste.rs/s/jisg7l/const_cast_necessary_evil">评论</a></p>
查看缓存全文
缓存时间: 2026/07/29 17:57
# 必要的恶——为什么乌鸦像写字台?
来源:https://www.elbeno.com/blog/?p=1858
我们不太喜欢`const_cast`。它很丑,甚至可能导致未定义行为。但不幸的是,有时又不得不使用它。即便不考虑那些不尊重`const`属性的C库,C++标准中至少也有一处要求你用到它。如果你有一个`std::priority_queue`,里面存放的是只移对象,你该如何从中取出对象呢?(因为它既不是Roach Motel®,也不是Hotel California……)
`pop`函数返回`void`。这毫无帮助。对于其他容器适配器,比如`std::stack`和`std::queue`,`top`/`front`/`back`函数返回的是可变引用。这些容器适配器不需要维护依赖于内部对象状态的不变式。但`std::priority_queue`的`top`函数返回的是`const`引用。`std::priority_queue`*不能*给你一个内部对象的可变引用,因为一旦给了,你就可以修改其中的对象,从而破坏堆的不变式。
所以你能做的唯一一件事,就是使用`const_cast`,暂时且强制地打破这个不变式,然后再恢复它。
```cpp
// top 只能给我们一个 const 引用
const T& obj = q.top();
// 我们必须去除 const 才能把对象移出来,
// 这打破了队列的不变式
T exfiltrated_obj = std::move(const_cast<T&>(obj));
// 现在应该立即恢复队列的不变式
q.pop();
```
容器适配器在标准中并不受待见:这个问题从C++11起就存在了。我猜,你就捏着鼻子用吧。
相似文章
C语言中在C++中仍然无法工作的构造——以及一些已发生变化的构造
一篇更新经典调查的博文,关于C语言中在C++中无法工作的构造,涵盖了C++20和C23标准中影响兼容性的变化。
从头构建现代C++中的快速无锁队列
一本关于在现代C++中实现快速无锁队列的指南,涵盖了无需锁的并发数据结构技术。
C++ 标准库在过去十五年间一直在自我撤步,证据公开
一份详细的目录,列出了从 C++11 到 C++26 期间被正式弃用、非正式不推荐或由于 ABI 约束实际上已损坏但无法修复的 C++ 标准库特性。文章指出,C++ 委员会推出一系列替代品来替换其自身特性的模式始终如一,其中包含一个基准测试,显示 Rust 和 C++ 标准库容器之间的 P99 延迟差异高达 58 倍。
std::function 与 copyable_function 的互转换
对 C++26 中 std::function 和 std::copyable_function 之间互转换的技术分析,讨论了实现方法和性能权衡,并特别指出 libstdc++ 目前采用了一种较次优的方法。
C++中老式C风格void*的优雅与简洁
文章讨论了在C++中使用C风格void*指针与uint8_t*和std::span传递内存块的优缺点,主张void*的简洁性和可读性。