std::midpoint(ptr1, ptr2) 是 C++20 唯一规避 ptr2 - ptr1 溢出的指针中点计算方式;手写 ptr1 + (ptr2 - ptr1) / 2 因 ptrdiff_t 减法溢出导致未定义行为,而 std::midpoint 绕过该减法峰值,要求两指针同类型、同数组且符合 one-past-the-end 规则。

std::midpoint(ptr1, ptr2) 是 C++20 中唯一被标准强制要求规避 ptr2 - ptr1 溢出的指针中点计算方式;手写 ptr1 + (ptr2 - ptr1) / 2 在超大数组下可能触发未定义行为,不能当作等价替代。
为什么 ptr1 + (ptr2 - ptr1) / 2 在指针算术里会崩
问题不在除法,而在减法:ptr2 - ptr1 返回 ptrdiff_t,其取值范围远小于地址跨度。例如在 64 位系统上,ptrdiff_t 通常是带符号 64 位整数(最大约 9.2e18),但某些巨型映射或 malloc 分配的缓冲区地址差可能接近 UINTPTR_MAX(1.8e19)。此时 ptr2 - ptr1 溢出,整个表达式变成未定义行为——不是“结果错”,而是编译器可随意优化、静默截断甚至删掉逻辑。
-
std::midpoint要求实现绕过该减法峰值,等价于先缩放偏移再叠加,不依赖ptrdiff_t能容纳全程距离 - 它不要求你手动检查
ptr2 >= ptr1,但若违反“同数组”前提(如两块malloc内存),行为仍为未定义——编译器不报错,运行时可能返回非法地址 -
nullptr只允许成对出现:std::midpoint(nullptr, nullptr)合法;std::midpoint(nullptr, p)不合法
std::midpoint(T*, T*) 的类型与内存布局硬性约束
它不是“地址平均器”,而是严格面向标准定义的指针算术:两个参数必须是同一类型的原生指针,且指向同一对象(或数组)及其 one-past-the-end 位置。
- 不接受
void*、const T*与T*混用(即使能隐式转换,模板实例化也会失败) -
std::vector::iterator、std::string::iterator等类指针类型直接传入会编译失败;必须显式转为原生指针:std::midpoint(&v[0], &v[0] + v.size())或std::midpoint(std::data(v), std::data(v) + v.size()) - C 风格数组可用
std::midpoint(arr, arr + N),但N必须 ≤ 数组长度,否则arr + N超出one-past-the-end就未定义 - 结构体成员地址(如
&s.a和&s.b)不能用——它们不是同一数组元素,标准未定义此类行为
二分查找中调用 std::midpoint 的典型安全模式
它只解决中点计算这一步的安全性,其余逻辑(空区间判断、有效性校验、迭代终止)仍需你负责。
- 必须提前检查指针有效性:
if (first == last) return not_found;,否则对空范围调用std::midpoint(first, last)虽合法(因last是one-past-the-end),但后续解引用会崩溃 - 示例安全写法:
auto mid = std::midpoint(begin, end);,其中begin和end是同一数组内合法指针,且end是one-past-the-end - 错误写法:
std::midpoint(v.begin(), v.end())编译失败;应改用std::midpoint(std::data(v), std::data(v) + v.size()) - 类型必须完全一致:
const int*和int*混用、void*、不同 cv 修饰均非法
编译与头文件常见踩坑点
很多团队在迁移时翻车,不是因为不会用函数,而是卡在基础配置和类型细节上。
- 头文件是
,不是或——忘加#include会导致编译失败,错误提示常为 “not declared in this scope” - 编译器必须启用 C++20:
GCC需-std=c++20,Clang同理;MSVC 19.28+支持,但需确认_HAS_CXX20宏开启 - 传入悬空指针或跨分配块指针不会编译报错,但运行时行为未定义——
std::midpoint不校验指针有效性,只保“算得对” - 它不解决业务语义问题:比如你传了两个合法但逻辑上不该参与中点计算的指针(如来自不同
new块),std::midpoint依然会返回一个地址,但这个地址大概率非法
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











