应避免用 vector mat = {{1,2}, {3,4}} 初始化,因其触发多次拷贝且内层 capacity 不可控;推荐 vector mat(rows, vector(cols, val)) 统一分配大小与初值,确保 size/capacity 一致,防止越界和扩容抖动。

vector> 初始化时别直接用 = {}
直接写 vector<vector>> mat = {{1,2}, {3,4}};</vector> 看似简洁,但底层会触发多次临时对象构造和拷贝(C++11 前尤其明显),在大矩阵或频繁初始化场景下有隐性开销。更关键的是,这种写法无法控制内层 vector 的容量(capacity),后续 push_back 容易反复扩容。
推荐做法是先确定外层数量,再逐个 resize 内层:
int rows = 3, cols = 4; vector<vector<int>> mat(rows, vector<int>(cols)); // 所有元素值为 0
如果需要非零初始值,用带默认值的构造:
vector<vector<int>> mat(rows, vector<int>(cols, -1)); // 全填 -1
-
vector<int>(cols)</int>构造出一个长度为cols、值全为 0 的 vector - 外层
rows个拷贝共享同一初始化逻辑,无运行时循环 - 所有内层 vector 的
size()和capacity()都等于cols,避免后续插入抖动
批量赋值前必须确认 size 匹配,否则越界静默失败
很多人习惯先 resize 外层,再用下标赋值,比如:
立即学习“C++免费学习笔记(深入)”;
mat.resize(3);
mat[0] = {1, 2, 3};
mat[1] = {4, 5};
这看似没问题,但若 mat[0] 原来是空的,赋值后它变成长度为 3 的 vector;而 mat[1] 变成长度为 2 —— 后续访问 mat[1][2] 就是未定义行为。更危险的是,编译器不报错,运行时可能只在特定优化等级下崩溃。
安全做法是:先统一设定每行大小,再逐元素赋值:
mat.resize(3, vector<int>(4)); // 每行固定 4 列
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
mat[i][j] = i * 4 + j;
}
}
-
resize(n, val)的第二个参数是“填充用的默认 vector”,不是单个元素值 - 如果某行后续列数不固定,改用
mat[i].assign({1,2,3})显式替换整行 - 永远不要依赖
mat[i][j] = x自动扩展mat[i]的 size —— vector 不支持自动 grow-on-access
resize 和 reserve 的分工必须分清
resize 改变的是 size(),即逻辑长度,会构造/析构元素;reserve 只预分配内存,不改变 size(),也不调用构造函数。嵌套 vector 中二者常被混用:
mat.reserve(100); // 错!这只是给外层 vector 预留空间,内层一个都没动 mat.resize(100); // 对!让外层有 100 行,每行默认为空 vector for (auto& row : mat) row.reserve(50); // 正确:逐行预留列空间
- 外层
reserve节省的是“增加行数”时的内存重分配,对内层无影响 - 内层
reserve必须显式循环调用,否则每次push_back都可能触发内层 vector 自身扩容 - 如果已知每行固定列数,优先用
resize(rows, vector<int>(cols))</int>,比先resize再循环reserve更简洁且等效
用 initializer_list 初始化小矩阵时注意类型推导陷阱
写 auto mat = {{1,2}, {3,4}}; 看起来方便,但 C++ 推导出的类型是 std::initializer_list<:initializer_list>></:initializer_list>,不是 vector<vector>></vector>。它不能调用 push_back、resize,也不能传给期望 vector 的函数。
若真要靠字面量初始化小矩阵,明确写出类型:
vector<vector<int>> mat = {{1,2}, {3,4}};
// 或 C++17 以上可简写为:
vector mat = vector<vector<int>>{{1,2}, {3,4}};
- 第一种写法最兼容,所有标准版本都支持
- 第二种依赖模板参数推导,某些老编译器(如 GCC 7.5 之前)可能失败
- 绝不要省略左侧类型直接用
auto—— 你会拿到一个只读、不可修改、生命周期受限的临时对象
嵌套 vector 最容易被忽略的点,其实是每一层的 size() 和 capacity() 是独立管理的。一次 resize 只影响一层,想控制整体内存布局,得逐层动手,没有银弹。


















