std::midpoint 仅对同符号整型和指针安全防溢出,整数版等价于 a + (b - a) / 2,指针版强制规避 ptrdiff_t 溢出;浮点版无优势,无符号类型有模回绕风险,类型不匹配或越界需手动校验。

直接用 std::midpoint 替换 (a + b) / 2 并不能自动规避溢出——它只在整数类型严格匹配、符号合理、且不用于浮点坐标时才真正起效;盲目套用反而导致编译失败或语义错位。
std::midpoint(int, int) 在坐标索引中为何能防溢出
它底层等价于 a + (b - a) / 2,全程避开加法峰值。比如计算格点坐标 std::midpoint(INT_MAX, INT_MAX - 1) 返回确定值 INT_MAX - 1,而 (INT_MAX + (INT_MAX - 1)) / 2 是未定义行为(UB)。
- 仅当两个参数为同一有符号整型(如都是
int或都显式转为long long)时,该路径才被标准保证安全 - 支持
a > b(如std::midpoint(10, 2)得6),数学语义正确,但需确认业务是否允许非升序输入 - 结果向下取整:
std::midpoint(-5, 2)返回-2(即floor((a + b) / 2.0)),和 C++ 整除一致 - 不提升类型:
std::midpoint(short{1}, short{3})返回short,避免隐式转换带来的截断风险
为什么传 size_t 坐标要格外小心
std::midpoint 对无符号类型(如 size_t、uint32_t)也合法,但减法按模算术回绕——std::midpoint(1U, 0U) 返回 0U,因为 (1U - 0U) / 2 == 0,再加 0U。这在环形缓冲区或哈希桶索引中可能符合预期,但在普通二维网格坐标中会违背直觉。
- 若坐标来自容器大小(如
v.size())、且可能接近SIZE_MAX,必须明确业务是否接受“模意义下中点” - 不要混用:传
std::midpoint(i, v.size())(i是int,v.size()是size_t)直接编译失败 - 统一类型推荐写法:
std::midpoint(static_cast,但需先确认(left), right) left >= 0 - 对负坐标场景(如地图偏移量),
size_t不适用,必须用有符号类型
std::midpoint(T*, T*) 是唯一不可替代的指针中点用途
这是它最刚性、最不可替代的价值点:计算大数组边界指针的中点时,std::midpoint(begin, end) 被标准强制要求规避 end - begin 超出 ptrdiff_t 范围导致的未定义行为;而手写 begin + (end - begin) / 2 不保这个减法安全。
- 必须是同一数组内指针(含 one-past-the-end):
std::midpoint(&v[0], &v[0] + v.size())✅,std::midpoint(&v[0], &w[0] + w.size())❌(跨容器) - 迭代器不支持:
std::midpoint(v.begin(), v.end())编译失败;应改用std::midpoint(std::data(v), std::data(v) + v.size()) - 类型必须完全一致:
const int*和int*混用、void*、不同 cv 修饰均非法 - 空容器要提前判断:
v.empty()为真时,&v[0]本身已非法,std::midpoint不做任何校验
float/double 坐标千万别用 std::midpoint
std::midpoint(float, float) 在 C++20 中存在,但只是 (a + b) / 2 的封装,不规避浮点溢出、不改善精度,某些情况下比手写更糟。
- 当
a = 1e30f、b = 1.0f时,a + b直接舍入为1e30f,结果仍是5e29f;而a + (b - a) * 0.5f更接近真实中点 - 不处理
NaN、inf,行为与裸运算一致,不会拦截或修正 - 真需要抗量级差异的浮点中点,优先分支判断:
if (std::abs(a) >= std::abs(b)) { return a + (b - a) * 0.5f; } else { return b + (a - b) * 0.5f; } - 或使用
std::fma(a, 0.5f, b * 0.5f)(需#include),利用融合乘加提升精度
真正容易被忽略的是:std::midpoint 只管“给定两个合法值,怎么算中点最安全”,它不检查索引是否越界、容器是否为空、指针是否有效、坐标是否在业务定义域内——这些语义层的校验,全得你自己写。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











