动态数组是在程序运行时根据需要分配和调整大小的数组。与静态数组不同,动态数组的大小不需要在编译时确定,可以根据程序的实际需求进行动态调整。
动态数组的基本概念
静态数组 vs 动态数组
#include <iostream>
#include <vector>
void demonstrateStaticVsDynamic() {
std::cout << "=== 静态数组 vs 动态数组 ===" << std::endl;
// 静态数组 - 编译时确定大小
int staticArray[5] = {1, 2, 3, 4, 5};
std::cout << "静态数组大小: " << sizeof(staticArray) / sizeof(staticArray[0]) << std::endl;
// 动态数组 - 运行时确定大小
int size;
std::cout << "请输入动态数组大小: ";
std::cin >> size;
// 使用 new 分配动态数组
int* dynamicArray = new int[size];
// 初始化动态数组
for (int i = 0; i < size; ++i) {
dynamicArray[i] = (i + 1) * 10;
}
std::cout << "动态数组内容: ";
for (int i = 0; i < size; ++i) {
std::cout << dynamicArray[i] << " ";
}
std::cout << std::endl;
// 释放动态数组内存
delete[] dynamicArray;
// 使用 std::vector(推荐方式)
std::vector<int> vectorArray(size);
for (int i = 0; i < size; ++i) {
vectorArray[i] = (i + 1) * 20;
}
std::cout << "vector 内容: ";
for (int value : vectorArray) {
std::cout << value << " ";
}
std::cout << std::endl;
}
int main() {
demonstrateStaticVsDynamic();
return 0;
}
手动实现动态数组
#include <iostream>
#include <stdexcept>
#include <algorithm>
template<typename T>
class DynamicArray {
private:
T* data; // 指向数据的指针
size_t size; // 当前元素数量
size_t capacity; // 当前容量
public:
// 构造函数
DynamicArray(size_t initial_capacity = 4)
: size(0), capacity(initial_capacity) {
data = new T[capacity];
std::cout << "创建动态数组,初始容量: " << capacity << std::endl;
}
// 析构函数
~DynamicArray() {
delete[] data;
std::cout << "销毁动态数组" << std::endl;
}
// 拷贝构造函数
DynamicArray(const DynamicArray& other)
: size(other.size), capacity(other.capacity) {
data = new T[capacity];
std::copy(other.data, other.data + size, data);
std::cout << "拷贝构造动态数组" << std::endl;
}
// 拷贝赋值操作符
DynamicArray& operator=(const DynamicArray& other) {
if (this != &other) {
delete[] data;
size = other.size;
capacity = other.capacity;
data = new T[capacity];
std::copy(other.data, other.data + size, data);
std::cout << "拷贝赋值动态数组" << std::endl;
}
return *this;
}
// 移动构造函数(C++11)
DynamicArray(DynamicArray&& other) noexcept
: data(other.data), size(other.size), capacity(other.capacity) {
other.data = nullptr;
other.size = 0;
other.capacity = 0;
std::cout << "移动构造动态数组" << std::endl;
}
// 移动赋值操作符(C++11)
DynamicArray& operator=(DynamicArray&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
size = other.size;
capacity = other.capacity;
other.data = nullptr;
other.size = 0;
other.capacity = 0;
std::cout << "移动赋值动态数组" << std::endl;
}
return *this;
}
// 添加元素
void push_back(const T& value) {
if (size >= capacity) {
resize();
}
data[size++] = value;
}
// 删除最后一个元素
void pop_back() {
if (size > 0) {
--size;
}
}
// 在指定位置插入元素
void insert(size_t index, const T& value) {
if (index > size) {
throw std::out_of_range("索引超出范围");
}
if (size >= capacity) {
resize();
}
// 移动元素为新元素腾出空间
for (size_t i = size; i > index; --i) {
data[i] = data[i - 1];
}
data[index] = value;
++size;
}
// 删除指定位置的元素
void erase(size_t index) {
if (index >= size) {
throw std::out_of_range("索引超出范围");
}
// 移动元素填补空隙
for (size_t i = index; i < size - 1; ++i) {
data[i] = data[i + 1];
}
--size;
}
// 访问元素
T& operator[](size_t index) {
return data[index];
}
const T& operator[](size_t index) const {
return data[index];
}
// 安全访问元素
T& at(size_t index) {
if (index >= size) {
throw std::out_of_range("索引超出范围");
}
return data[index];
}
const T& at(size_t index) const {
if (index >= size) {
throw std::out_of_range("索引超出范围");
}
return data[index];
}
// 获取大小和容量
size_t getSize() const { return size; }
size_t getCapacity() const { return capacity; }
bool empty() const { return size == 0; }
// 清空数组
void clear() {
size = 0;
}
// 预留容量
void reserve(size_t new_capacity) {
if (new_capacity > capacity) {
T* new_data = new T[new_capacity];
std::copy(data, data + size, new_data);
delete[] data;
data = new_data;
capacity = new_capacity;
std::cout << "预留容量: " << capacity << std::endl;
}
}
// 调整大小
void resize(size_t new_size, const T& value = T()) {
if (new_size > capacity) {
reserve(new_size);
}
if (new_size > size) {
// 填充新元素
for (size_t i = size; i < new_size; ++i) {
data[i] = value;
}
}
size = new_size;
}
// 打印数组内容
void print() const {
std::cout << "数组 [大小:" << size << ", 容量:" << capacity << "]: ";
for (size_t i = 0; i < size; ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
private:
// 扩容
void resize() {
size_t new_capacity = capacity == 0 ? 1 : capacity * 2;
T* new_data = new T[new_capacity];
std::copy(data, data + size, new_data);
delete[] data;
data = new_data;
capacity = new_capacity;
std::cout << "数组扩容到: " << capacity << std::endl;
}
};
int main() {
std::cout << "=== 自定义动态数组演示 ===" << std::endl;
DynamicArray<int> arr;
// 添加元素,观察扩容过程
for (int i = 1; i <= 10; ++i) {
arr.push_back(i * 10);
arr.print();
}
// 插入元素
std::cout << "\n插入元素:" << std::endl;
arr.insert(2, 999);
arr.print();
// 删除元素
std::cout << "\n删除元素:" << std::endl;
arr.erase(2);
arr.print();
// 访问元素
std::cout << "\n访问元素:" << std::endl;
std::cout << "arr[3] = " << arr[3] << std::endl;
try {
std::cout << "arr.at(15) = " << arr.at(15) << std::endl;
} catch (const std::exception& e) {
std::cout << "异常: " << e.what() << std::endl;
}
// 调整大小
std::cout << "\n调整大小:" << std::endl;
arr.resize(15, 888);
arr.print();
return 0;
}
std::vector 详解
概述
std::vector
是 C++ 标准库中最常用的动态数组容器,提供了高效的随机访问、动态扩容和丰富的操作接口。它是大多数场景下替代原始数组的最佳选择。
特点
- 动态扩容:自动管理内存,根据需要调整容量
- 连续存储:元素在内存中连续存储,缓存友好
- 随机访问:O(1) 时间复杂度访问任意元素
- 类型安全:模板化,编译时类型检查
- RAII:自动内存管理,无需手动释放
vector 的基本操作
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
void demonstrateVectorBasics() {
std::cout << "=== std::vector 基本操作 ===" << std::endl;
// 1. 创建 vector - 多种初始化方式
std::vector<int> vec1; // 空 vector
std::vector<int> vec2(5); // 5 个默认值(0)
std::vector<int> vec3(5, 10); // 5 个值为 10 的元素
std::vector<int> vec4{1, 2, 3, 4, 5}; // 初始化列表
std::vector<int> vec5(vec4); // 拷贝构造
std::vector<int> vec6(vec4.begin(), vec4.end()); // 迭代器范围构造
std::cout << "vec3: ";
for (int x : vec3) std::cout << x << " ";
std::cout << std::endl;
std::cout << "vec4: ";
for (int x : vec4) std::cout << x << " ";
std::cout << std::endl;
// 2. 添加元素
vec1.push_back(100);
vec1.push_back(200);
vec1.push_back(300);
// C++11 emplace_back - 直接在容器中构造元素
vec1.emplace_back(400);
std::cout << "vec1 after push_back: ";
for (int x : vec1) std::cout << x << " ";
std::cout << std::endl;
// 3. 插入元素
vec1.insert(vec1.begin() + 1, 150); // 在位置 1 插入 150
vec1.insert(vec1.end(), {500, 600}); // 在末尾插入多个元素
vec1.insert(vec1.begin(), 3, 50); // 在开头插入 3 个 50
std::cout << "vec1 after insert: ";
for (int x : vec1) std::cout << x << " ";
std::cout << std::endl;
// 4. 删除元素
vec1.pop_back(); // 删除最后一个元素
vec1.erase(vec1.begin() + 1); // 删除位置 1 的元素
vec1.erase(vec1.begin() + 2, vec1.begin() + 4); // 删除范围内的元素
std::cout << "vec1 after erase: ";
for (int x : vec1) std::cout << x << " ";
std::cout << std::endl;
// 5. 访问元素
if (!vec1.empty()) {
std::cout << "vec1[0] = " << vec1[0] << std::endl;
std::cout << "vec1.at(1) = " << vec1.at(1) << std::endl; // 有边界检查
std::cout << "vec1.front() = " << vec1.front() << std::endl;
std::cout << "vec1.back() = " << vec1.back() << std::endl;
// 使用数据指针访问
int* data_ptr = vec1.data();
std::cout << "通过 data() 访问第一个元素: " << *data_ptr << std::endl;
}
// 6. 大小和容量
std::cout << "size: " << vec1.size() << std::endl;
std::cout << "capacity: " << vec1.capacity() << std::endl;
std::cout << "max_size: " << vec1.max_size() << std::endl;
std::cout << "empty: " << (vec1.empty() ? "true" : "false") << std::endl;
// 7. 预留容量和调整大小
vec1.reserve(20);
std::cout << "after reserve(20), capacity: " << vec1.capacity() << std::endl;
size_t old_size = vec1.size();
vec1.resize(10, 999); // 如果增大,新元素值为 999
std::cout << "after resize(10, 999): ";
for (int x : vec1) std::cout << x << " ";
std::cout << std::endl;
// 8. 清空和交换
std::vector<int> temp_vec{11, 22, 33};
vec1.swap(temp_vec); // 交换两个 vector 的内容
std::cout << "after swap: ";
for (int x : vec1) std::cout << x << " ";
std::cout << std::endl;
vec1.clear(); // 清空所有元素
std::cout << "after clear - size: " << vec1.size() << ", capacity: " << vec1.capacity() << std::endl;
// 9. 缩减容量
vec1.shrink_to_fit(); // 请求释放未使用的内存
std::cout << "after shrink_to_fit - capacity: " << vec1.capacity() << std::endl;
}
vector 的高级操作
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <random>
#include <functional>
void demonstrateVectorAdvanced() {
std::cout << "\n=== std::vector 高级操作 ===" << std::endl;
std::vector<int> vec{5, 2, 8, 1, 9, 3, 7, 4, 6};
std::cout << "原始 vector: ";
for (int x : vec) std::cout << x << " ";
std::cout << std::endl;
// 1. 排序操作
std::vector<int> sorted_vec = vec;
std::sort(sorted_vec.begin(), sorted_vec.end());
std::cout << "升序排序: ";
for (int x : sorted_vec) std::cout << x << " ";
std::cout << std::endl;
std::sort(sorted_vec.begin(), sorted_vec.end(), std::greater<int>());
std::cout << "降序排序: ";
for (int x : sorted_vec) std::cout << x << " ";
std::cout << std::endl;
// 部分排序
std::vector<int> partial_vec = vec;
std::partial_sort(partial_vec.begin(), partial_vec.begin() + 3, partial_vec.end());
std::cout << "部分排序(前3个最小): ";
for (int x : partial_vec) std::cout << x << " ";
std::cout << std::endl;
// 2. 查找操作
auto it = std::find(vec.begin(), vec.end(), 8);
if (it != vec.end()) {
std::cout << "线性查找: 找到 8 在位置 " << (it - vec.begin()) << std::endl;
}
// 在有序序列中二分查找
std::vector<int> binary_vec = vec;
std::sort(binary_vec.begin(), binary_vec.end());
bool found = std::binary_search(binary_vec.begin(), binary_vec.end(), 8);
std::cout << "二分查找 8: " << (found ? "找到" : "未找到") << std::endl;
auto lower_it = std::lower_bound(binary_vec.begin(), binary_vec.end(), 5);
std::cout << "lower_bound(5) 位置: " << (lower_it - binary_vec.begin()) << std::endl;
// 条件查找
auto condition_it = std::find_if(vec.begin(), vec.end(), [](int x) { return x > 7; });
if (condition_it != vec.end()) {
std::cout << "第一个大于7的数: " << *condition_it << std::endl;
}
// 3. 计数操作
int count_greater_5 = std::count_if(vec.begin(), vec.end(), [](int x) { return x > 5; });
std::cout << "大于5的元素个数: " << count_greater_5 << std::endl;
// 4. 数值操作
int sum = std::accumulate(vec.begin(), vec.end(), 0);
std::cout << "元素总和: " << sum << std::endl;
int product = std::accumulate(vec.begin(), vec.end(), 1, std::multiplies<int>());
std::cout << "元素乘积: " << product << std::endl;
// 5. 变换操作
std::vector<int> squared_vec;
squared_vec.reserve(vec.size());
std::transform(vec.begin(), vec.end(), std::back_inserter(squared_vec),
[](int x) { return x * x; });
std::cout << "平方后: ";
for (int x : squared_vec) std::cout << x << " ";
std::cout << std::endl;
// 6. 过滤操作
std::vector<int> filtered_vec;
std::copy_if(vec.begin(), vec.end(), std::back_inserter(filtered_vec),
[](int x) { return x % 2 == 0; });
std::cout << "偶数过滤: ";
for (int x : filtered_vec) std::cout << x << " ";
std::cout << std::endl;
// 7. 去重操作
std::vector<int> unique_vec = vec;
std::sort(unique_vec.begin(), unique_vec.end());
unique_vec.erase(std::unique(unique_vec.begin(), unique_vec.end()), unique_vec.end());
std::cout << "去重后: ";
for (int x : unique_vec) std::cout << x << " ";
std::cout << std::endl;
// 8. 随机操作
std::random_device rd;
std::mt19937 g(rd());
std::vector<int> shuffle_vec = vec;
std::shuffle(shuffle_vec.begin(), shuffle_vec.end(), g);
std::cout << "随机打乱: ";
for (int x : shuffle_vec) std::cout << x << " ";
std::cout << std::endl;
// 9. 最值操作
auto min_it = std::min_element(vec.begin(), vec.end());
auto max_it = std::max_element(vec.begin(), vec.end());
auto minmax_pair = std::minmax_element(vec.begin(), vec.end());
std::cout << "最小值: " << *min_it << ", 位置: " << (min_it - vec.begin()) << std::endl;
std::cout << "最大值: " << *max_it << ", 位置: " << (max_it - vec.begin()) << std::endl;
std::cout << "最小值: " << *minmax_pair.first << ", 最大值: " << *minmax_pair.second << std::endl;
}
vector 的迭代器使用
void demonstrateVectorIterators() {
std::cout << "\n=== std::vector 迭代器使用 ===" << std::endl;
std::vector<int> vec{10, 20, 30, 40, 50};
// 1. 基本迭代器
std::cout << "正向遍历: ";
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
std::cout << "反向遍历: ";
for (auto it = vec.rbegin(); it != vec.rend(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// 2. const 迭代器
const std::vector<int>& const_vec = vec;
std::cout << "const 迭代器: ";
for (auto it = const_vec.cbegin(); it != const_vec.cend(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// 3. 迭代器算术
auto it = vec.begin();
std::advance(it, 2); // 前进 2 步
std::cout << "advance(2) 后的值: " << *it << std::endl;
auto distance = std::distance(vec.begin(), vec.end());
std::cout << "距离: " << distance << std::endl;
// 4. 迭代器修改元素
std::cout << "修改前: ";
for (int x : vec) std::cout << x << " ";
std::cout << std::endl;
std::for_each(vec.begin(), vec.end(), [](int& x) { x *= 2; });
std::cout << "修改后: ";
for (int x : vec) std::cout << x << " ";
std::cout << std::endl;
}
性能优化技巧
void demonstrateVectorPerformance() {
std::cout << "\n=== std::vector 性能优化 ===" << std::endl;
// 1. 预留容量避免重新分配
std::vector<int> vec1, vec2;
// 坏的做法 - 可能多次重新分配
for (int i = 0; i < 1000; ++i) {
vec1.push_back(i);
}
// 好的做法 - 预先分配足够空间
vec2.reserve(1000);
for (int i = 0; i < 1000; ++i) {
vec2.push_back(i);
}
std::cout << "vec1 capacity: " << vec1.capacity() << std::endl;
std::cout << "vec2 capacity: " << vec2.capacity() << std::endl;
// 2. emplace_back vs push_back
std::vector<std::pair<int, std::string>> pairs;
pairs.reserve(3);
// push_back - 创建临时对象再复制/移动
pairs.push_back(std::make_pair(1, "one"));
// emplace_back - 直接在容器中构造
pairs.emplace_back(2, "two");
pairs.emplace_back(3, "three");
std::cout << "pairs size: " << pairs.size() << std::endl;
// 3. 避免不必要的复制
std::vector<int> source{1, 2, 3, 4, 5};
// 坏的做法 - 复制
std::vector<int> dest1 = source;
// 好的做法 - 移动(如果不再需要 source)
std::vector<int> dest2 = std::move(source); // source 变为空
std::cout << "dest1 size: " << dest1.size() << std::endl;
std::cout << "dest2 size: " << dest2.size() << std::endl;
std::cout << "source size after move: " << source.size() << std::endl;
// 4. 使用 shrink_to_fit 释放多余内存
std::vector<int> large_vec(1000, 42);
std::cout << "large_vec capacity before resize: " << large_vec.capacity() << std::endl;
large_vec.resize(10);
std::cout << "large_vec capacity after resize(10): " << large_vec.capacity() << std::endl;
large_vec.shrink_to_fit();
std::cout << "large_vec capacity after shrink_to_fit: " << large_vec.capacity() << std::endl;
}
自定义类型的 vector
#include <string>
class Person {
public:
std::string name;
int age;
Person(const std::string& n, int a) : name(n), age(a) {}
// 为了使用某些算法,可能需要比较运算符
bool operator<(const Person& other) const {
return age < other.age;
}
bool operator==(const Person& other) const {
return name == other.name && age == other.age;
}
friend std::ostream& operator<<(std::ostream& os, const Person& p) {
os << p.name << "(" << p.age << ")";
return os;
}
};
void demonstrateVectorCustomType() {
std::cout << "\n=== std::vector 自定义类型 ===" << std::endl;
std::vector<Person> people;
// 使用 emplace_back 直接构造
people.emplace_back("Alice", 25);
people.emplace_back("Bob", 30);
people.emplace_back("Charlie", 20);
std::cout << "原始顺序: ";
for (const auto& person : people) {
std::cout << person << " ";
}
std::cout << std::endl;
// 按年龄排序
std::sort(people.begin(), people.end());
std::cout << "按年龄排序: ";
for (const auto& person : people) {
std::cout << person << " ";
}
std::cout << std::endl;
// 查找特定的人
auto it = std::find(people.begin(), people.end(), Person("Bob", 30));
if (it != people.end()) {
std::cout << "找到: " << *it << std::endl;
}
// 使用自定义比较器按姓名排序
std::sort(people.begin(), people.end(),
[](const Person& a, const Person& b) {
return a.name < b.name;
});
std::cout << "按姓名排序: ";
for (const auto& person : people) {
std::cout << person << " ";
}
std::cout << std::endl;
}
常见陷阱和注意事项
void demonstrateVectorPitfalls() {
std::cout << "\n=== std::vector 常见陷阱 ===" << std::endl;
// 1. 迭代器失效
std::vector<int> vec{1, 2, 3, 4, 5};
std::cout << "迭代器失效示例:" << std::endl;
auto it = vec.begin() + 2; // 指向元素 3
std::cout << "插入前 it 指向: " << *it << std::endl;
vec.insert(vec.begin(), 0); // 在开头插入,可能导致重新分配
// 此时 it 可能已失效,使用它是未定义行为
// std::cout << *it << std::endl; // 危险!
// 正确做法:重新获取迭代器或使用索引
it = vec.begin() + 3; // 重新定位到元素 3
std::cout << "插入后重新定位 it 指向: " << *it << std::endl;
// 2. 范围检查
std::cout << "\n范围检查示例:" << std::endl;
std::vector<int> small_vec{1, 2, 3};
try {
std::cout << "使用 at() 访问越界索引:" << std::endl;
std::cout << small_vec.at(5) << std::endl; // 抛出异常
} catch (const std::out_of_range& e) {
std::cout << "捕获异常: " << e.what() << std::endl;
}
// operator[] 不进行边界检查,可能导致未定义行为
// std::cout << small_vec[5] << std::endl; // 危险!
// 3. 容量 vs 大小
std::cout << "\n容量与大小的区别:" << std::endl;
std::vector<int> cap_vec;
cap_vec.reserve(10);
std::cout << "reserve(10) 后 - size: " << cap_vec.size()
<< ", capacity: " << cap_vec.capacity() << std::endl;
// 错误:认为 reserve 会创建元素
// cap_vec[5] = 42; // 危险!size 仍为 0
// 正确:使用 resize 或 push_back 创建元素
cap_vec.resize(5);
cap_vec[4] = 42;
std::cout << "resize(5) 后 - size: " << cap_vec.size() << std::endl;
// 4. vector<bool> 的特殊性
std::cout << "\nvector<bool> 特殊性:" << std::endl;
std::vector<bool> bool_vec(5, true);
// vector<bool> 不是真正的容器,它的引用不是 bool&
auto& ref = bool_vec[0]; // 实际上是代理对象
std::cout << "bool_vec[0] = " << bool_vec[0] << std::endl;
// 如需真正的 bool 容器,使用 std::deque<bool> 或 std::vector<char>
}
完整示例程序
int main() {
std::cout << "C++ std::vector 完整教程" << std::endl;
std::cout << "========================" << std::endl;
try {
demonstrateVectorBasics();
demonstrateVectorAdvanced();
demonstrateVectorIterators();
demonstrateVectorPerformance();
demonstrateVectorCustomType();
demonstrateVectorPitfalls();
std::cout << "\n教程完成!" << std::endl;
} catch (const std::exception& e) {
std::cerr << "异常: " << e.what() << std::endl;
return 1;
}
return 0;
}
总结
std::vector
是 C++ 中最重要的容器之一,掌握其用法对于编写高效的 C++ 程序至关重要。主要要点包括:
- 正确的初始化方式:根据需求选择合适的构造函数
- 性能优化:使用
reserve()
预分配内存,用emplace_back()
替代push_back()
- 迭代器安全:注意迭代器失效的情况
- 边界检查:使用
at()
进行安全访问,或确保索引有效 - 内存管理:理解容量和大小的区别,适时使用
shrink_to_fit()
通过掌握这些概念和技巧,你可以充分发挥 std::vector
的威力,编写出既安全又高效的 C++ 代码。