在 C++ 标准库中,std::vector 是最常用的动态数组容器。它可以方便地在运行时根据需要增删元素,但默认只是一维的。若要实现可变长度的多维数组(如二维、三维等),我们可以通过嵌套 std::vector 或使用 std::vector<std::vector<...>> 的方式。下面给出几种实现思路,并对每种方法的优缺点做简要分析。
1. 嵌套 std::vector
#include <vector>
#include <iostream>
int main() {
// 创建一个 3x4 的二维数组,初始值为 0
std::vector<std::vector<int>> matrix(3, std::vector<int>(4, 0));
// 访问和修改元素
matrix[1][2] = 42;
// 动态扩容
matrix.push_back(std::vector <int>(4, 0)); // 增加一行
matrix[0].push_back(7); // 在第一行尾部添加一个元素
// 打印矩阵
for(const auto& row : matrix) {
for(int val : row) {
std::cout << val << ' ';
}
std::cout << '\n';
}
return 0;
}
优点
- 代码简洁,利用标准容器提供的功能。
- 直接支持任意深度嵌套,易于扩展。
- 通过
reserve或resize可以提前预分配内存,减少重分配。
缺点
- 内存碎片化:每一行都是独立的
vector,在内存上不连续,访问速度受缓存友好性影响。 - 对于高维度频繁访问,索引链的开销略大。
2. 一维 std::vector + 手动索引映射
将多维数组映射到一维空间,利用索引公式计算位置:
#include <vector>
#include <iostream>
class MultiDimArray {
public:
MultiDimArray(const std::vector <size_t>& dims)
: dims_(dims) {
size_t total = 1;
strides_.resize(dims.size());
for (int i = dims.size() - 1; i >= 0; --i) {
strides_[i] = total;
total *= dims[i];
}
data_.resize(total);
}
int& operator()(const std::vector <size_t>& indices) {
size_t offset = 0;
for (size_t i = 0; i < dims_.size(); ++i)
offset += indices[i] * strides_[i];
return data_[offset];
}
private:
std::vector <size_t> dims_;
std::vector <size_t> strides_;
std::vector <int> data_;
};
int main() {
MultiDimArray arr({3, 4, 5}); // 3x4x5 的三维数组
// 设置值
arr({1, 2, 3}) = 99;
// 读取值
std::cout << arr({1, 2, 3}) << '\n';
return 0;
}
优点
- 内存连续,缓存友好,访问速度更快。
- 可以根据需求随时调整维度大小。
- 适合数值计算、矩阵运算等高性能场景。
缺点
- 需要手动维护维度和跨度(stride)信息,代码稍显繁琐。
- 当维度变化频繁时,需要重新计算跨度并重新分配内存,成本较高。
3. 使用 boost::multi_array
如果项目中允许使用第三方库,可以直接使用 boost::multi_array:
#include <boost/multi_array.hpp>
#include <iostream>
int main() {
boost::multi_array<int, 3> arr(boost::extents[3][4][5]);
arr[1][2][3] = 77;
std::cout << arr[1][2][3] << '\n';
}
优点
- 语法直观,像原生多维数组一样访问。
- 内置维度检查,安全性更高。
- 支持切片、转置等高级功能。
缺点
- 依赖外部库,可能不适合所有项目。
- 编译时模板膨胀,编译时间稍长。
4. 结论
- 小型项目、快速原型:建议使用嵌套
std::vector,因为代码最简单易懂。 - 高性能计算:采用一维
std::vector+ 索引映射或boost::multi_array,以获得更好的内存局部性。 - 跨平台或需要大量维度支持:可以考虑封装自己的
MultiDimArray类,保持接口统一。
无论哪种实现方式,都需要注意:
- 维度合法性检查:避免越界访问导致未定义行为。
- 内存管理:若使用手动分配,确保释放;若使用
std::vector,自动管理。 - 性能测试:在真实数据量下做基准测试,验证是否满足性能需求。
通过上述方法,你可以在 C++ 中灵活、有效地实现可变长度的多维数组,满足从简易脚本到高性能科学计算的各种需求。祝编码愉快!