std::distance 能用于原生指针是因为指针满足 randomaccessiterator 概念,支持 o(1) 减法运算;但要求两指针指向同一数组或其尾后位置,否则行为未定义。

std::distance 为什么能用于原生指针
std::distance 是一个模板函数,底层根据迭代器类型自动选择算法:对随机访问迭代器(比如 int*、char*)直接做减法;对其他类型(如链表迭代器)则逐个递增计数。原生指针满足 RandomAccessIterator 要求,所以能用,且是 O(1) 时间。
关键点在于:两个指针必须指向同一数组(或紧邻的尾后位置),否则行为未定义 —— 这不是编译错误,但运行时可能出错或返回垃圾值。
正确调用 std::distance 的前提条件
必须确保:
- 两个指针类型相同,且都指向同一块连续内存(例如同一
std::vector的data()、同一 C 数组) - 第一个指针不能位于第二个指针之后(即
first ),否则结果为负,但函数本身不检查 - 允许其中一个是尾后指针(如
&arr[n]或v.end()对应的指针),这是合法且常见用法
错误示例:std::distance(p1, p2) 中 p1 和 p2 分别指向两个不同 malloc 分配的内存块 —— 结果不可预测。
和直接相减(p2 - p1)有什么区别
对原生指针而言,std::distance(p1, p2) 和 p2 - p1 在语义和结果上完全等价,生成的汇编也几乎一样。区别只在表达意图和泛化能力:
-
p2 - p1是 C 风格写法,直观但仅适用于指针;换成std::list::iterator就编译不过 -
std::distance是统一接口,同一行代码可适配vector、deque、list等所有容器的迭代器 - 当不确定迭代器类别(比如模板函数中),用
std::distance更安全、更通用
所以如果你写的是泛型代码,或者未来可能换容器,优先用 std::distance;如果只是临时算两个 int* 差距,p2 - p1 更轻量、无额外函数调用开销。
常见误用与编译/运行时陷阱
最常踩的坑不是语法错误,而是逻辑越界:
- 传入空指针(
nullptr):编译通过,但运行时触发未定义行为(通常段错误) - 指针来自不同分配单元(如分别
new int[10]和new int[5]):结果是任意整数,无法解释 - 使用
const_iterator和iterator混合(如std::distance(v.cbegin(), v.end())):C++11 起允许,但早期标准可能失败;现代编译器一般没问题 - 忘记包含头文件:
#include <iterator></iterator>—— 否则编译报std::distance未声明
调试时如果得到奇怪的大数(比如 9223372036854775807),大概率是其中一个指针为 nullptr 或已释放。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











