用std::vector是最直接安全的做法,每行可独立指定大小、自动内存管理;手动new/delete易出错且不推荐;需注意其非连续内存布局及缓存局部性问题。

用 std::vector<:vector>></:vector> 是最直接、安全的做法
C++ 没有原生支持“列数可变的不规则二维数组”的语法(比如 int arr[][?]> 这种写法是非法的),但 std::vector<:vector>></:vector> 天然适配:每行可以独立指定大小,内存自动管理,不会越界或泄漏。
常见错误是试图用 new int*[N] 手动分配指针数组再逐行 new,结果忘记释放、漏掉某一行、或搞错 delete[] 层级——这种写法在现代 C++ 中既没必要也不推荐。
- 初始化时可指定行数,每行长度自由:
std::vector<:vector>> grid = { {1, 2}, {3, 4, 5, 6}, {7} };</:vector> - 运行时动态追加:
grid.emplace_back(std::initializer_list<int>{8, 9, 10});</int> - 访问前务必检查
grid[i].size(),因为grid[i][j]不做边界校验(和原生数组一样)
如果必须用原始指针,std::unique_ptr 能避免手动 delete
极少数场景(如对接 C 接口、性能敏感且已确认 vector 开销不可接受),需要裸指针但又不想裸写 new/delete。这时用 std::unique_ptr 管理外层数组,每行仍用 std::unique_ptr 或 std::vector。
错误示范:int** arr = new int*[3]; for(...) arr[i] = new int[len]; —— 析构逻辑分散、异常不安全、容易漏删。
- 更稳妥的原始指针方案(RAII 化):
auto rows = std::make_unique<:unique_ptr>[]>(3); rows[0] = std::make_unique<int>(2); rows[1] = std::make_unique<int>(4); rows[2] = std::make_unique<int>(1);</int></int></int></:unique_ptr>
- 注意:不能用
std::unique_ptr<int></int>(C++ 不允许不完整二维数组类型) - 每行长度仍需单独记录,
rows[i].get()返回的是int*,没有长度信息
std::vector<:vector>></:vector> 的性能和内存布局要注意什么
它不是连续内存块:外层 vector 存的是内层 vector 对象(每个含指针+size+capacity),内层数据各自堆分配。这意味着:
- 随机访问某元素(
grid[i][j])是两次指针解引用,比连续二维数组稍慢,但通常可忽略 - 遍历所有元素时局部性较差,缓存命中率低于
std::vector<int></int>扁平化存储 - 如果所有行长度相近且总大小固定,考虑扁平化 + 行偏移索引:
std::vector<int> flat = {...}; std::vector<size_t> row_offsets = {0, 2, 6, 7}; // 每行起始位置 // grid[i][j] → flat[row_offsets[i] + j]</size_t></int>
别用 std::array 或模板参数硬编码列数
std::array<:array n>, M></:array> 要求每行列数严格相同,编译期固定,完全不满足“列数可变”需求。试图用模板推导不同长度会失败:
错误代码:
template<size_t... ns> auto make_jagged() { /* ... */ } // 无法让每个 <code>std::array</code> 有不同的 <code>N</code></size_t...>
这类写法要么编译不过,要么退化成同长数组的容器(比如 std::vector<:array>></:array>),失去不规则意义。
真正需要编译期确定形状时,应该重新评估是否真的需要“不规则”——否则就是设计矛盾。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











