C++如何使用STL向量vector存储数据

来源:站长查询作者:Robin头衔:草根站长
导读:本期聚焦于小伙伴创作的《C++如何使用STL向量vector存储数据》,敬请观看详情。想把一堆同类型的数据塞进一个能自动变长的容器里,却不想手动管理内存?STL里的vector就是干这事的标准答案。它底层是一段连续内存,支持随机访问,尾部增删效率很高。声明时用vectorint v就能建一个整型动态数组,用push_back把数据依次放进去,用size看长度,用下标或at取元素。和原生数组比,它不用你算容量,也不会轻易越界崩溃。本文会讲清初始化、增删查改、遍历和迭代器失效这些实操要点,并附上可直接抄的代码,帮你少踩坑。

在C++开发中,vector是最常用的序列容器之一,它封装了动态数组的能力,让开发者无需关心内存的申请与释放,就能安全地存储和管理一组相同类型的元素。无论是读取文件中的多行文本,还是缓存传感器上报的数值,vector都能以简洁的接口完成数据暂存与后续处理。

C++如何使用STL向量vector存储数据

一、vector的基本初始化方式

使用vector前需要包含头文件<vector>,并通过std命名空间访问。最基础的空向量声明方式为std::vector<int> v;,此时容器内没有任何元素,容量也为0。当第一次调用push_back时,vector会向堆申请一小块连续内存。

除了空向量,还可以用指定长度和初始值的方式构造。例如std::vector<int> v(10, 0);会创建包含10个整数的向量,每个元素都被初始化为0。也可以用初始化列表直接赋值,如std::vector<int> v{1, 2, 3};,这种方式在C++11及之后非常直观。下面给出几种常见初始化代码:

#include <vector>
#include <iostream>

int main() {
    // 空向量
    std::vector<int> a;
    // 长度为5,初值均为100
    std::vector<int> b(5, 100);
    // 初始化列表
    std::vector<int> c{2, 4, 6, 8};

    std::cout << "b size: " << b.size() << std::endl;
    std::cout << "c[0]: " << c[0] << std::endl;
    return 0;
}

从上面的代码可以看出,vector的构造非常灵活。需要注意的是,使用圆括号(5, 100)和花括号{5, 100}含义完全不同,前者表示五个元素都是100,后者表示两个元素分别为5和100,这是初学者容易混淆的地方。

二、向vector中存入数据

最常用的写入方法是push_back,它把元素追加到向量尾部。如果当前容量不足,vector会将原有数据拷贝到更大的新内存块中,并释放旧内存。这种自动扩容机制让用户不必预先估算准确大小,但频繁扩容会带来性能开销。

若已经知道大概要存多少数据,可以提前调用reserve预留容量,避免多次重新分配。C++11还提供了emplace_back,它直接在容器尾部构造对象,减少一次临时对象拷贝,对自定义类型尤其有用。以下示例展示不同写入方式:

#include <vector>
#include <string>

struct User {
    int id;
    std::string name;
    User(int i, std::string n) : id(i), name(n) {}
};

int main() {
    std::vector<User> users;
    users.reserve(3);            // 预留空间,减少扩容
    users.push_back(User(1, "Tom"));
    users.emplace_back(2, "Lucy"); // 直接构造,效率更高
    return 0;
}

在上面的代码中,reserve只改变容量不改变大小,所以不能用下标访问未实际存入的元素。push_back和emplace_back都使size增加1,但emplace_back通过参数包直接转发给构造函数,避免了User临时对象的生成与拷贝。

三、访问与遍历存储的数据

vector支持随机访问,使用下标运算符[]或成员函数at都能获取元素。区别在于,[]不做边界检查,越界时行为未定义;at会抛出std::out_of_range异常,更安全。遍历时可用传统for循环、范围for或迭代器。

范围for语法最简洁,适合只读或顺序修改;若需要在遍历中删除元素,则必须使用迭代器并小心处理失效问题。下面的例子演示三种遍历:

#include <vector>
#include <iostream>

int main() {
    std::vector<int> v{10, 20, 30};

    // 下标遍历
    for (size_t i = 0; i < v.size(); ++i) {
        std::cout << v[i] << " ";
    }
    std::cout << std::endl;

    // 范围for
    for (int val : v) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    // 迭代器
    for (auto it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << " ";
    }
    return 0;
}

实际项目中,如果只需要读取数据,优先用范围for,代码可读性最好。当容器可能为空时,先用empty判断再访问,可以防止at抛出异常或[]越界。

四、删除元素与迭代器失效

vector提供pop_back删除尾部元素,也可以用erase删除中间或指定区间元素。但必须注意,除尾部外任何位置的删除都会使被删位置之后的迭代器、引用和指针失效,因为后续元素会向前移动填补空位。

在循环中删除元素时,正确做法是让erase返回新的有效迭代器。下面代码展示如何删除所有偶数,同时避免迭代器失效导致的未定义行为:

#include <vector>
#include <iostream>

int main() {
    std::vector<int> v{1, 2, 3, 4, 5, 6};
    for (auto it = v.begin(); it != v.end(); ) {
        if (*it % 2 == 0) {
            it = v.erase(it); // erase返回下一个有效迭代器
        } else {
            ++it;
        }
    }
    for (int x : v) std::cout << x << " ";
    return 0;
}

如果不接收erase的返回值而继续使用旧迭代器,程序可能崩溃或产生错误结果。此外,调用clear只会清空元素不改变容量,若想释放多余内存,可借助swap技巧或与空向量交换来真正回收空间。

五、vector存储自定义类型的注意事项

当vector存放的是自定义类对象时,该类最好具备可拷贝或可移动语义,因为扩容时容器会拷贝或移动原有元素。如果类中含有不能安全拷贝的资源(如文件句柄),应显式定义移动构造和移动赋值,或禁止拷贝改用指针容器。

对于多态对象,不要直接存基类实例,而应使用std::vector<std::unique_ptr<Base>>这类智能指针向量,既保证内存自动释放,又支持多态调用。如下示例简要说明:

#include <vector>
#include <memory>

class Shape {
public:
    virtual void draw() const = 0;
    virtual ~Shape() = default;
};

class Circle : public Shape {
public:
    void draw() const override {}
};

int main() {
    std::vector<std::unique_ptr<Shape>> shapes;
    shapes.push_back(std::make_unique<Circle>());
    return 0;
}

使用智能指针向量能有效规避手动delete带来的泄漏风险,同时unique_ptr不可拷贝只能移动,迫使开发者明确资源所有权,是现代C++推荐的存储方式。

六、性能与使用建议总结

vector在尾部插入删除的时间复杂度为均摊O(1),随机访问为O(1),但中间插入删除为O(n)。因此它适合读多写少、主要在尾部追加的场景。如果频繁在头部或中间插入,应考虑list或deque。

合理运用reserve、emplace_back和移动语义,可以显著提升vector处理大量数据时的效率。理解迭代器失效规则,则能帮助写出健壮的增删逻辑,让vector真正成为可靠的数据存储工具。

vectorSTL动态数组修改时间:2026-08-07 01:48:36

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。