在C++的世界里,数组是最基础的数据结构,但原生数组有个致命缺陷——大小固定。想象你正在开发一个学生管理系统,最初预估班级最多50人,于是声明了int students[50]。但当转学生不断加入时,这个预设的"魔法数字"就成了紧箍咒。这就是vector诞生的背景。
vector是标准模板库(STL)中的动态数组实现,它解决了三大痛点:
new/deletecpp复制// 传统数组的局限
int arr[5] = {1,2,3};
arr[3] = 4; // 合法
arr[5] = 6; // 越界!危险!
// vector的灵活
std::vector<int> vec = {1,2,3};
vec.push_back(4); // 安全扩容
关键理解:vector的底层仍是连续内存空间,通过分配新内存+元素迁移实现扩容,这解释了为什么随机访问效率高(O(1))而中间插入可能低效(O(n))。
vector提供多种构造方式,适应不同场景:
cpp复制// 空vector(后续通过push_back填充)
std::vector<std::string> names;
// 预分配空间(避免频繁扩容)
std::vector<double> temperatures(365); // 365个0.0
// 初始化列表(C++11起)
std::vector<char> vowels = {'a', 'e', 'i', 'o', 'u'};
// 拷贝构造
std::vector<int> source = {1,2,3};
std::vector<int> copy(source);
// 移动构造(C++11)
std::vector<int> moved(std::move(source)); // source现在为空
特殊技巧:
reserve()预分配空间可避免多次扩容开销std::vector::emplace_back比push_back更高效安全访问是vector的核心优势:
cpp复制std::vector<int> fib = {1, 1, 2, 3, 5};
// 下标访问(不检查边界)
int third = fib[2];
// at()方法(边界检查)
try {
int sixth = fib.at(5); // 抛出std::out_of_range
} catch(...) { /* 处理异常 */ }
// 现代遍历方式
for(int num : fib) { /* 范围for循环 */ }
for(auto it = fib.begin(); it != fib.end(); ++it) { /* 迭代器 */ }
性能提示:
operator[]比at()快约10倍(无检查开销),生产环境在确保安全时优先使用[]。
理解size、capacity的区别至关重要:
cpp复制std::vector<int> nums;
nums.reserve(100); // capacity=100, size=0
nums.push_back(42); // size=1
std::cout << "占用空间: " << nums.size()
<< "/" << nums.capacity();
// 主动缩容(C++11)
nums.shrink_to_fit(); // capacity=size
扩容策略(常见实现):
size == capacity时,分配新空间并迁移元素cpp复制std::vector<std::string> words = {"apple", "banana"};
// 尾部操作(O(1))
words.push_back("cherry");
words.pop_back();
// 中间插入(O(n))
words.insert(words.begin() + 1, "blueberry");
// 删除元素
words.erase(words.begin()); // 删除"apple"
words.clear(); // 清空
高效插入技巧:
insert(pos, first, last)emplace系列避免临时对象构造vector的某些操作会使迭代器失效:
cpp复制std::vector<int> data = {10,20,30};
auto it = data.begin();
data.push_back(40); // 可能引起扩容
// 此时it可能指向已释放的内存!
// 安全做法:操作后重新获取迭代器
it = data.begin();
失效场景总结:
存储类对象时需注意:
cpp复制class Student {
std::string name;
int score;
public:
Student(std::string n, int s) : name(n), score(s) {}
};
std::vector<Student> class;
class.emplace_back("Alice", 95); // 直接构造
关键要点:
vector是STL算法的绝佳搭档:
cpp复制#include <algorithm>
std::vector<int> nums = {3,1,4,2,5};
// 排序
std::sort(nums.begin(), nums.end());
// 查找
auto found = std::find(nums.begin(), nums.end(), 4);
// 删除特定条件元素
nums.erase(std::remove_if(nums.begin(), nums.end(),
[](int x){ return x%2 == 0; }), nums.end());
cpp复制void test_reserve() {
const int N = 1000000;
// 不预分配
auto start1 = std::chrono::high_resolution_clock::now();
std::vector<int> v1;
for(int i=0; i<N; ++i) v1.push_back(i);
auto end1 = std::chrono::high_resolution_clock::now();
// 预分配
auto start2 = std::chrono::high_resolution_clock::now();
std::vector<int> v2;
v2.reserve(N);
for(int i=0; i<N; ++i) v2.push_back(i);
auto end2 = std::chrono::high_resolution_clock::now();
// 结果显示:预分配通常快3-5倍
}
cpp复制std::vector<std::string> getLargeStrings() {
std::vector<std::string> temp;
// ...填充大量数据...
return temp; // C++11起触发移动而非拷贝
}
// 调用方高效接收
auto strings = getLargeStrings(); // 零拷贝
虽然vector万能,但特定场景其他容器更优:
cpp复制std::vector<int> createVector() {
std::vector<int> local = {1,2,3};
return local; // 正确:返回值优化或移动
}
int& getFirst() {
std::vector<int> local = {1,2,3};
return local[0]; // 错误:返回局部对象引用!
}
cpp复制std::vector<int> v1 = {1,2,3};
std::vector<int> v2 = {4,5};
// 危险:v1.end()不属于v2的迭代器范围
v2.insert(v2.end(), v1.begin(), v1.end()); // 安全
// v2.insert(v2.begin(), v1.begin(), v1.end()); // 也安全
cpp复制std::vector<int> nums = {1,2,3};
// nums.push_back("hello"); // 编译错误
// 解决方案:
nums.push_back(std::stoi("42")); // 显式转换
cpp复制struct Pixel {
uint8_t r, g, b;
};
class Image {
std::vector<Pixel> pixels;
size_t width, height;
public:
Image(size_t w, size_t h) : width(w), height(h) {
pixels.resize(width * height);
}
void invertColors() {
for(auto& p : pixels) {
p.r = 255 - p.r;
p.g = 255 - p.g;
p.b = 255 - p.b;
}
}
};
cpp复制class GameObject {
// ...游戏对象属性...
};
class GameWorld {
std::vector<std::unique_ptr<GameObject>> entities;
public:
void addEntity(std::unique_ptr<GameObject> obj) {
entities.push_back(std::move(obj));
}
void removeDestroyed() {
auto new_end = std::remove_if(entities.begin(), entities.end(),
[](const auto& obj) { return obj->isDestroyed(); });
entities.erase(new_end, entities.end());
}
};
cpp复制#include <ranges>
std::vector<int> nums = {1,2,3,4,5};
// 过滤偶数并平方
auto result = nums | std::views::filter([](int x){ return x%2==0; })
| std::views::transform([](int x){ return x*x; });
for(int x : result) {
std::cout << x << " "; // 输出:4 16
}
cpp复制#include <coroutine>
generator<int> range(int start, int end) {
for(int i=start; i<=end; ++i)
co_yield i;
}
void use_range() {
for(int i : range(1,5)) {
std::cout << i << " "; // 输出:1 2 3 4 5
}
}