最稳妥方式是用std::vector实现矩阵乘法:需断言左矩阵列数等于右矩阵行数,结果矩阵维度为rows_A × cols_B,三重循环采用i-k-j顺序以提升缓存友好性,并严格校验空矩阵与越界访问。

用 std::vector 实现二维矩阵乘法最稳妥
直接用裸数组容易越界、难管理内存,std::vector<:vector>> 是实际项目中最常用也最安全的选择。它自动处理内存释放,支持动态尺寸,且与现代 C++ 工具链(如调试器、ASan)兼容性好。
关键点在于:乘法要求左矩阵列数等于右矩阵行数,否则结果未定义——必须在运行时检查,不能只靠注释或文档约定。
- 初始化结果矩阵为
rows_A × cols_B,所有元素设为 0 - 三层循环顺序是
i(A 行)、k(公共维度)、j(B 列),这个顺序对缓存友好 - 别写成
i-j-k,那样会频繁跳地址,实测慢 2–3 倍
std::vector<:vector>> matmul(
const std::vector<:vector>>& A,
const std::vector<:vector>>& B) {
size_t rows_A = A.size();
size_t cols_A = A[0].size();
size_t rows_B = B.size();
size_t cols_B = B[0].size();
if (cols_A != rows_B) throw std::invalid_argument("dim mismatch");
<p>std::vector<:vector>> C(rows_A, std::vector<double>(cols_B, 0.0));
for (size_t i = 0; i </double></:vector></p></:vector></:vector></:vector>
用 std::valarray 做简单数值计算够用但有坑
std::valarray 支持切片和广播语义,写起来短,但不适用于通用矩阵乘法:它没有原生二维形状概念,apply() 和 shift() 难以映射到矩阵索引逻辑;而且多数编译器对其优化有限,性能常不如手写三重循环。
如果你只是做固定小尺寸(比如 3×3 变换矩阵),直接展开写更清晰、更快、更容易向量化。
- 不要试图用
valarray模拟二维索引——容易下标错位,调试困难 - 如果真要用,必须配合
gslice手动构造行列视图,代码可读性急剧下降 - VS 和 GCC 对
valarray的 ABI 不完全一致,跨平台分发二进制时慎用
遇到 segmentation fault 大概率是索引没校验
最常见的崩溃不是算法错,而是访问了空 vector 或越界:比如 A[0].size() 在 A 为空时触发未定义行为;或者循环里用了 而不是 。
- 永远先检查
!A.empty() && !A[0].empty(),再取维度 - 用
at()替代[]做开发期调试(会抛std::out_of_range) - Clang/GCC 加
-fsanitize=address,undefined能立刻定位越界点
需要高性能?别自己手写三重循环
除非矩阵极小(openblas、Intel MKL 或 Apple Accelerate。它们做了指令级优化(AVX512/FMA)、多线程、内存预取,单核性能通常是手写代码的 5–10 倍,多核下差距更大。
- C++ 封装库如
xtensor或armadillo底层就绑 BLAS,语法接近 NumPy - 自己用 BLAS 时注意:CBLAS 是列主序(Fortran 风格),传参顺序和内存布局要匹配
- 链接时漏
-lopenblas或符号未导出,会导致运行时报undefined symbol: cblas_dgemm
手写循环只适合教学、调试或特殊稀疏/定制格式场景;真实业务中硬刚 BLAS,大概率是在重复解决别人已优化十年的问题。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











