std::vector<double> 动态数组详解
·
std::vector<double> 是 C++ 标准模板库(STL)中定义的一个动态数组容器,专门用于存储 double(双精度浮点数)类型的元素。其核心含义是一个能够在运行时动态改变大小的、类型安全的、连续存储的数组,它封装了底层的内存管理,极大地简化了数值序列(如坐标、采样数据、系数矩阵等)的操作 。
为了清晰理解其构成和特性,可参考下表:
| 组成部分 | 含义与说明 |
|---|---|
std:: | 命名空间,表示 vector 是 C++ 标准库中的组件,以区别于用户自定义的同名类。 |
vector | 模板类名,是 STL 中提供动态数组功能的容器类模板。 |
<double> | 模板参数,指定了该 vector 容器将要存储的元素数据类型为 double。 |
1. 核心特性与底层机制
std::vector<double> 的核心优势在于其动态性和易用性。与 C 风格的原生数组(如 double arr[10])或定长数组 std::array<double, N> 相比,vector 的大小(即元素数量)不是在编译期固定,而是在程序运行时根据需要动态增长或收缩 。
- 连续内存存储:
vector内部使用一块连续的内存空间来存储所有double元素。这意味着可以通过指针算术或迭代器高效地访问任意元素,并且对缓存友好,访问速度通常很快 。 - 自动内存管理:当向
vector中添加元素导致当前容量不足时,它会自动分配一块更大的新内存,将原有元素复制(或移动)过去,并释放旧内存。这个过程对使用者是透明的,有效避免了手动管理内存的复杂性和内存泄漏风险 。 - 类型安全:由于模板的实例化,
std::vector<double>只能存储double类型的值。编译器会在编译时进行类型检查,防止错误类型的元素被插入,提高了代码的健壮性 。
2. 基本用法与代码示例
以下通过具体代码展示 std::vector<double> 的常见操作。
2.1 创建与初始化
#include <iostream>
#include <vector> // 必须包含的头文件
int main() {
// 1. 创建一个空的 vector
std::vector<double> vec1;
// 2. 创建时指定初始大小和初始值
std::vector<double> vec2(5); // 包含5个元素,每个元素默认初始化为 0.0
std::vector<double> vec3(5, 3.14); // 包含5个元素,每个元素初始化为 3.14
// 3. 使用初始化列表(C++11及以上)
std::vector<double> vec4 = {1.1, 2.2, 3.3, 4.4, 5.5};
// 4. 通过迭代器范围初始化(例如,从数组复制)
double c_array[] = {6.6, 7.7, 8.8};
std::vector<double> vec5(c_array, c_array + 3); // 复制 c_array 的前3个元素
return 0;
}
2.2 添加与访问元素
#include <iostream>
#include <vector>
int main() {
std::vector<double> data;
// 1. 在末尾添加元素
data.push_back(10.5); // data: [10.5]
data.push_back(20.1); // data: [10.5, 20.1]
data.push_back(30.8); // data: [10.5, 20.1, 30.8]
// 2. 访问元素
// 使用下标运算符(不进行边界检查,访问越界行为未定义)
double first = data[0]; // first = 10.5
// 使用 at() 成员函数(进行边界检查,越界抛出 std::out_of_range 异常)
double second = data.at(1); // second = 20.1
// 使用 front() 和 back() 访问首尾元素
double front = data.front(); // front = 10.5
double back = data.back(); // back = 30.8
// 3. 遍历元素(C++11 基于范围的 for 循环)
std::cout << "Vector elements: ";
for (double val : data) {
std::cout << val << " "; // 输出: 10.5 20.1 30.8
}
std::cout << std::endl;
// 4. 使用迭代器遍历
std::cout << "Using iterator: ";
for (auto it = data.begin(); it != data.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
2.3 容量与大小管理
#include <iostream>
#include <vector>
int main() {
std::vector<double> vec = {1.0, 2.0, 3.0};
// 1. 获取当前元素数量
std::cout << "size: " << vec.size() << std::endl; // 输出: 3
// 2. 获取当前已分配的内存容量(可容纳的元素数量,>= size)
std::cout << "capacity: " << vec.capacity() << std::endl;
// 3. 检查是否为空
bool isEmpty = vec.empty(); // 返回 false
// 4. 调整大小
vec.resize(5); // 将大小调整为5,新增的两个元素被默认初始化为 0.0
// 此时 vec: [1.0, 2.0, 3.0, 0.0, 0.0]
vec.resize(2); // 将大小调整为2,末尾的元素被丢弃
// 此时 vec: [1.0, 2.0]
vec.resize(4, 9.9); // 将大小调整为4,新增的两个元素被初始化为 9.9
// 此时 vec: [1.0, 2.0, 9.9, 9.9]
// 5. 预留容量(避免多次 push_back 导致的重分配,提升性能)
vec.reserve(100); // 预分配至少能容纳100个元素的内存,但 size() 不变
return 0;
}
2.4 与其他数据结构的交互(示例)
std::vector<double> 常与其他数据结构进行转换,例如从 QVector<QPointF> 中提取所有 x 坐标 ,或与 Eigen 库的向量进行互转 。
// 示例1:从 QVector<QPointF> 提取 x 坐标到 std::vector<double>
#include <QPointF>
#include <QVector>
#include <vector>
QVector<QPointF> qtPoints = {QPointF(1.0, 2.0), QPointF(3.0, 4.0), QPointF(5.0, 6.0)};
std::vector<double> xCoords;
xCoords.reserve(qtPoints.size()); // 预分配空间以提高效率
for (const auto& point : qtPoints) {
xCoords.push_back(point.x());
}
// 此时 xCoords 包含 [1.0, 3.0, 5.0]
// 示例2:使用 std::transform 算法进行转换(更函数式风格)
#include <algorithm>
std::vector<double> yCoords;
yCoords.resize(qtPoints.size());
std::transform(qtPoints.begin(), qtPoints.end(), yCoords.begin(),
[](const QPointF& p) { return p.y(); });
// 此时 yCoords 包含 [2.0, 4.0, 6.0]
3. 性能与注意事项
- 随机访问:通过索引访问元素(
operator[])的时间复杂度是 O(1),效率极高 。 - 尾部插入/删除:
push_back()和pop_back()的平均时间复杂度是 O(1),但在需要重新分配内存时是 O(n) 。 - 中间插入/删除:在任意位置(非尾部)插入或删除元素,需要移动后续所有元素,时间复杂度是 O(n)。
- 内存连续性:其内存连续性使得它可以与期望 C 风格数组指针的 C 函数或 API 交互。可以通过
&vec[0]或vec.data()(C++11)获取指向底层数组的指针 。但需注意,在vector发生内存重分配后,所有迭代器、指针和引用都会失效。 - 与
std::array的选择:如果需要编译期已知的固定大小数组,且对性能有极致要求,应选择std::array<double, N>。如果需要动态改变大小,则std::vector<double>是标准选择 。
总结:std::vector<double> 是 C++ 中处理动态 double 类型序列的首选容器。它提供了接近原生数组的性能,同时具备自动内存管理、动态大小调整、丰富的成员函数和迭代器支持等现代特性,是科学计算、图形处理、数值分析等领域存储浮点数数据的基石 。
参考来源
- 从 QVector<QPointF>提取 x 和 y 坐标到 std::vector<double> 的方法
- 「C/C++」C++STL容器库 之 std::tuple 多变元组
- memcpy一段内存到std::vector
- 传说的向量结构 STL+std::vector;
- Eigen::vector与std::vector的相互转换
- c++ 中的容器 vector 与数组 array
更多推荐




所有评论(0)