HOWTO · C++
在 C++ 中从指向向量的指针访问成员函数
了解如何在 C++ 中通过指针调用 std::vector 成员、将向量指针传递给函数,以及遍历其元素。
本页内容
要通过指针调用 C++ 向量的成员,可使用 ptr->member;等价写法是 (*ptr).member。指针必须指向向量对象本身。用 & 获取该对象的地址后,就可以通过任一表达式调用 size()、at() 等成员。下面的示例还会把指针传给函数,并通过它读取每个值。
使用 -> 通过指针访问向量
声明指针时,在向量类型后加上 *。对于整数向量,该类型是 std::vector<int>*。如果 values 是一个已存在的向量,&values 就是它的地址;将这个地址赋给指针后,指针便指向该向量。这不会复制向量,也不会创建另一个集合。
箭头运算符将解引用指针和选择成员这两步合在一起。因此,ptr->size() 会对 ptr 所指向的向量调用 size()。也可以把同一个指针传给参数类型匹配的函数。在完整示例中,report_size 接收指向常量向量的指针,因为它只读取向量。const 限定会阻止该函数通过参数修改向量,但不会改变指针的传递方式。
运行此示例:
#include <cstddef>
#include <iostream>
#include <vector>
void report_size(const std::vector<int>* ptr) {
std::cout << "Count: " << ptr->size() << '\n';
}
int main() {
std::vector<int> values{10, 20, 30};
const std::vector<int>* ptr = &values;
report_size(ptr);
for (std::size_t i = 0; i < ptr->size(); ++i) {
std::cout << (*ptr).at(i) << '\n';
}
}
Count: 3
10
20
30
运行结果会先输出向量大小,再将每个值单独输出一行。向量是自动存储期的局部变量,指针只会在该向量仍处于作用域内时使用。在自己的程序中,请确保指针的生命周期不超过它所保存地址对应对象的生命周期。
使用 (*ptr).member 通过指针访问向量
表达式 (*ptr).member 会先解引用 ptr,得到向量对象,然后用 . 选择该对象的成员。括号不可省略:如果没有括号,点运算符会先作用于 ptr,这不是我们要执行的操作。对于向量成员,(*ptr).size() 和 ptr->size() 的含义相同。箭头写法更简洁;解引用再使用点号的写法则把这两个操作明确地写了出来。
在上面的示例中,(*ptr).at(i) 会先解引用向量指针,再按索引访问元素。成员函数仍然是对向量调用的,而 at(i) 返回所选整数。阅读代码时要区分这两者:ptr 的类型是指向向量的指针,而 (*ptr).at(i) 表示一个元素值。如果函数需要处理整个向量,就传入指向向量的指针;如果只需要一个元素,则使用元素引用或适当的元素指针。
通过指向向量的指针遍历元素
循环使用 ptr->size() 作为结束条件,并通过 (*ptr).at(i) 访问每个值。这两个操作都是通过指向向量的指针完成的。也可以将按索引调用成员函数的写法改为箭头形式 ptr->at(i);它选择的是同一个向量成员。从 <cstddef> 引入的 std::size_t 是无符号类型,适合表示向量大小和索引。
指向向量的指针不同于向量迭代器,也不同于指向单个元素的指针。本例中的指针指向整个 std::vector<int> 对象。迭代器是容器提供的遍历位置;元素指针则指向某个已存储的值。按索引循环能将这些角色区分开来,并适用于需要索引的场景。如果只需访问每个值,也可以对 *ptr 使用范围 for 循环;不过这种写法遍历的是向量本身,并不会在每一步都演示通过指针调用成员。
由于示例在遍历时不会修改向量,按索引访问很直接。如果程序在遍历期间插入或删除元素,就需要重新考虑循环逻辑:这些操作可能改变向量大小,也可能使指向其元素的引用、指针或迭代器失效。指向向量对象的指针仍然指向该对象,但这并不能保证元素位置保持不变。每次使用该指针时都要确保向量仍然存活,并根据程序执行的修改选择合适的遍历方式。