std::distance 返回 signed 类型(如 std::ptrdiff_t)而非 size_t,因其需支持负距离(如反向遍历);vector 中为 O(1),list 中为 O(n),因前者迭代器支持减法,后者仅支持增减操作。

std::distance 为什么返回 long 而不是 size_t?
因为 std::distance 要支持反向遍历和负偏移——比如从 end() 往回走到 begin(),结果得是负数。而 size_t 是无符号类型,没法表示负距离。所以它用的是带符号整型,通常是 long 或 std::ptrdiff_t(后者才是标准规定的返回类型)。
常见错误现象:auto d = std::distance(it1, it2); int x = d; —— 在 64 位系统上如果 std::ptrdiff_t 是 long long,直接赋给 int 可能截断。
- 始终用
std::iterator_traits<It>::difference_type或直接用auto接收返回值 - 不要假设它是
int或size_t;尤其在做指针算术或容器索引转换时要小心符号问题 - 随机访问迭代器(如
vector::iterator)下std::distance是 O(1),但对list这类双向迭代器是 O(n)
vector 和 list 调用 std::distance 的性能差异有多大?
差别本质来自迭代器类别:vector 迭代器支持 operator-,list 迭代器只支持 ++/--,std::distance 必须靠循环计数。
使用场景举例:想判断两个 list::iterator 是否“相距不到 5 步”,写 std::distance(a, b) 看似简洁,实际每次调用都可能遍历最多 5 次节点——不如手动走 5 步并提前退出。
立即学习“C++免费学习笔记(深入)”;
-
vector、string、原生指针:O(1),底层就是last - first -
list、forward_list:O(n),必须逐个递增起始迭代器直到等于终点 - 若需频繁测距,优先考虑用索引(
vector)或改用支持随机访问的容器
std::distance 在自定义迭代器里怎么正确实现?
如果你写了可随机访问的迭代器(比如封装了 raw pointer),必须重载 operator-,否则 std::distance 会退化到泛型版本(即循环计数),哪怕你的迭代器逻辑上支持 O(1) 计算。
错误示范:迭代器类里只实现了 operator++ 和 operator==,没实现 operator- → std::distance 就当它是输入迭代器用。
- 随机访问迭代器必须提供
difference_type operator-(const self& other) const - 返回类型必须和
std::iterator_traits<It>::difference_type一致(通常用std::ptrdiff_t) - 别忘了在
std::iterator_traits特化中正确声明iterator_category = std::random_access_iterator_tag
用 std::distance 算两个 vector::iterator 的距离,结果为负正常吗?
完全正常,只要第一个迭代器在第二个“后面”。比如:auto it1 = v.end(); auto it2 = v.begin(); auto d = std::distance(it1, it2); —— 结果是负数,约等于 -v.size()。
容易踩的坑是拿这个值直接当数组下标用:v[d],这会越界甚至触发未定义行为。因为 d 是负的,而 vector::operator[] 不检查符号。
- 确保左迭代器不晚于右迭代器,或显式处理符号:
if (d - 更安全的做法:用
std::abs(d)配合方向判断,而不是直接参与索引运算 - 调试时打印
std::cout 前先确认两个迭代器所属同一容器且有效——跨容器或悬垂迭代器会导致未定义行为
最常被忽略的一点:std::distance 对无效迭代器不报错,也不抛异常,它只是按内存布局瞎算——结果看起来像数字,但毫无意义。









