用std::vector做二维数组更安全,因其支持运行时尺寸、避免内存泄漏、提供.at()边界检查;初始化用vector(rows, vector(cols, 0)),访问优先用i,调试用.at(i).at(j)捕获越界。

用 std::vector 做二维数组比原生 int[N][M] 更安全
原生 C 风格二维数组(如 int a[100][100])在函数传参时维度必须固定,且无法动态调整大小;一旦矩阵尺寸来自输入或配置,就容易越界或编译报错。用 std::vector<:vector>></:vector> 虽有轻微开销,但能避免内存泄漏、支持运行时尺寸、天然边界检查(配合 .at())。
实操建议:
- 初始化:用
std::vector<:vector>> mat(rows, std::vector<int>(cols, 0));</int></:vector> - 访问元素优先用
mat[i][j](简洁),调试阶段可换mat.at(i).at(j)捕获越界异常 - 避免嵌套
push_back构造大矩阵——先预留容量:mat.reserve(rows); for (int i = 0; i
operator* 重载实现矩阵乘法要严格校验维度
矩阵乘法要求左矩阵列数等于右矩阵行数,否则无定义。不校验就直接计算,轻则结果全零,重则访问非法内存(尤其用原生数组时)。
关键点:
立即学习“C++免费学习笔记(深入)”;
- 在乘法函数开头加断言:
assert(left[0].size() == right.size()); - 结果矩阵维度是
left.size() × right[0].size(),别写反 - 三重循环顺序推荐
i-j-k(外层行、中层结果列、内层求和索引),利于 CPU 缓存局部性;i-k-j容易 cache miss - 示例核心片段:
for (int i = 0; i < left.size(); ++i) for (int j = 0; j < right[0].size(); ++j) { res[i][j] = 0; for (int k = 0; k < left[0].size(); ++k) res[i][j] += left[i][k] * right[k][j]; }
用 std::valarray 或 Eigen 库替代手写乘法?
纯手写适合教学或极简嵌入场景;工程中应优先考虑成熟库——它们做了向量化、分块、多线程等优化,性能远超朴素三重循环。
选择参考:
-
std::valarray是标准库内置,轻量但接口生硬,不推荐初学者直接用(比如乘法需手动 reshape + apply) -
Eigen是事实标准:头文件即用,支持表达式模板(A * B + C不生成临时对象),且自动向量化;安装只需解压头文件目录,#include <eigen></eigen>即可 - 若不能引入第三方,至少把乘法封装成独立函数,参数用
const std::vector<:vector>>&</:vector>避免拷贝
常见错误:混淆行主序与列主序,或误用指针模拟二维数组
用 int* data = new int[rows * cols] 模拟二维数组时,data[i][j] 是非法语法;正确访问是 data[i * cols + j]。更麻烦的是:如果按列遍历(i 内层、j 外层),缓存命中率暴跌,小矩阵可能慢 3–5 倍。
容易踩的坑:
- 传参时把
int**当二维数组用——它只是指针数组,每行内存不一定连续,sizeof失效,malloc分配方式极易出错 - 用
std::vector<int></int>平铺存储却忘了行列映射关系,导致[i][j]计算错位 - 忘记初始化结果矩阵为 0,残留垃圾值参与累加
矩阵乘法本身逻辑简单,真正复杂的是内存布局选择、维度安全性、以及是否值得为性能/可维护性切换到专业线性代数库——这些决策点比循环怎么写影响更大。











