无法访问vector<vector<?>>元素,求二维向量赋值正确方法
问题描述
我定义了如下类,其唯一成员为vector<vector<struct Pixel>>:
struct Pixel { float r, g, b; }; class Test { private: vector<vector<struct Pixel>> pixels; public: void read(std::string filename); };
在read方法中,我先从文件读取数据存入一维vector:
std::vector<pixel> v; while(getline(file, line_pixels)) { if(line_pixels.size() > 0 && line_pixels.at(0) != '#') { std::stringstream ss(line_pixels); std::string value; while(getline(ss, value, ' ')) { pixel p; p.r = p.g = p.b = stoi(value); v.emplace_back(p); } } }
之后尝试将一维vector的数据转存到二维vectorpixels,两种实现方式均出现段错误:
第一种方式,访问pixels元素时触发段错误:
int index = 0; size_t h = stoi(height), w = stoi(width); for(size_t i=0; i<h; i++) { std::vector<pixel> row; for(size_t j=0; j<w; j++) row.push_back(v[index++]); pixels.push_back(row); }
第二种方式,执行resize语句时触发段错误:
size_t h = stoi(height), w = stoi(width); pixels.resize(h); for(size_t i=0; i<h; i++) pixels[i].resize(w); for(size_t i=0; i<v.size(); i++) { int row = i / w; int col = i % w; pixels[row][col] = v[i]; }
请问正确的实现方式是什么?
更新
完整代码分为两个项目:一个包含实现read方法的Netpbm和Bitmap类,另一个项目调用前者的方法。
问题分析与正确实现
段错误的核心原因集中在这几点:
- 类型不匹配:代码混用大小写不一致的
Pixel和pixel,C++强类型特性会导致未定义行为。 - 尺寸有效性缺失:
stoi(height)/stoi(width)可能得到负数、超大值等无效数据,或一维vectorv的元素总数不等于h*w,引发越界访问。 - 读取逻辑隐患:文件读取的像素数量与预期尺寸不匹配,后续操作触发越界。
修正后的实现步骤
1. 统一类型命名
将所有pixel改为Pixel,同时注意把int类型的像素值转为float(匹配Pixel成员类型):
// 修正一维vector的类型 std::vector<Pixel> v; while(getline(file, line_pixels)) { if(line_pixels.size() > 0 && line_pixels.at(0) != '#') { std::stringstream ss(line_pixels); std::string value; while(getline(ss, value, ' ')) { Pixel p; // 显式转换为float,避免隐式转换问题 p.r = p.g = p.b = static_cast<float>(stoi(value)); v.emplace_back(p); } } }
2. 校验尺寸与像素数量合法性
转换前先确认尺寸有效,且像素总数匹配,从根源避免越界:
// 转换并校验height、width int h_int = stoi(height); int w_int = stoi(width); if (h_int <= 0 || w_int <= 0) { throw std::invalid_argument("无效的图像尺寸"); } size_t h = static_cast<size_t>(h_int); size_t w = static_cast<size_t>(w_int); // 校验像素总数与尺寸是否匹配 if (v.size() != h * w) { throw std::runtime_error("像素数量与图像尺寸不匹配"); }
3. 安全转换为二维vector(推荐优化后的第二种方式)
// 清空原有数据,避免残留干扰 pixels.clear(); // 初始化二维vector的行 pixels.resize(h); for (size_t i = 0; i < h; ++i) { // 初始化每行的列数 pixels[i].resize(w); } // 填充数据(已校验过总数,不会越界) for (size_t i = 0; i < v.size(); ++i) { size_t row = i / w; size_t col = i % w; pixels[row][col] = v[i]; }
也可以用优化后的第一种方式:
pixels.clear(); size_t index = 0; for (size_t i = 0; i < h; ++i) { std::vector<Pixel> row; row.reserve(w); // 提前预留空间,提升效率 for (size_t j = 0; j < w; ++j) { row.push_back(v[index++]); } pixels.push_back(row); }
额外注意事项
- 确保文件已正确打开,否则
getline会失败导致v为空,后续操作必然出错。 - 若height/width是从文件读取的字符串,建议先做trim处理,避免多余空白字符导致
stoi抛出异常。
内容的提问来源于stack exchange,提问作者Kleber Mota
相关产品推荐
相关产品推荐

