读取流中每行首个数字并跳过其余内容的最优实现方式
读取每行首个数字的实现优化分析
需求场景
需要从流中读取每行的首个整数,跳过该行剩余所有内容。例如输入字符串123 123 456 asdf\n234 ewdwedwed,最终要生成包含{123, 234}的std::vector<int>。
初始实现(使用std::getline)
最初的实现代码如下:
int main() { std::stringstream ss { "123 123 456 asdf\n234 ewdwedwed" }; std::vector<int> values; int value; std::string skip; while (ss >> value) { values.push_back(value); std::getline(ss, skip); } return 0; }
优化思路的疑惑
你担心std::getline会把该行剩余数据全部复制到临时字符串skip中,造成不必要的内存消耗,因此考虑替换为使用std::peek和std::ignore的实现:
while (ss >> value) { values.push_back(value); while (ss.peek() != '\n'){ ss.ignore(); } }
两种实现的对比与优化建议
1. 内存消耗对比
你的顾虑完全合理:std::getline会将当前位置到换行符之间的所有字符读取并存储到字符串中,当单行剩余内容极大时,会额外占用大量内存存储无用数据。而std::ignore直接跳过字符,不需要额外分配内存存储这些内容,内存效率明显更高。
2. 备选实现的潜在问题
你给出的peek+ignore循环存在两个小问题:
- 当流提前遇到
EOF(而非换行符)时,ss.peek()返回EOF,此时!= '\n'的条件成立,会执行ss.ignore(),这会触发流的failbit,导致下一次ss >> value直接失败。 - 循环只跳过到换行符为止,但没有跳过换行符本身——虽然
>>运算符会自动跳过空白字符(包括换行),不会影响后续读取,但严谨性不足。
3. 更优的实现方式
其实可以直接使用std::ignore的重载版本,一次性跳过到换行符(或EOF),写法更简洁,也能避免上述问题:
#include <iostream> #include <sstream> #include <vector> #include <limits> int main() { std::stringstream ss { "123 123 456 asdf\n234 ewdwedwed" }; std::vector<int> values; int value; while (ss >> value) { values.push_back(value); // 跳过最多max个字符,直到遇到换行符或EOF ss.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); } // 可选:验证结果 for (int v : values) { std::cout << v << " "; } return 0; }
这个实现的优势:
- 没有额外内存消耗,直接跳过无用字符
- 自动处理
EOF情况,不会触发错误位 - 代码简洁,可读性强
总结
如果在意内存消耗,优先选择std::ignore的重载版本,它兼顾了内存效率、代码简洁性和鲁棒性,比你给出的两种实现都更优。
内容的提问来源于stack exchange,提问作者qloq
相关产品推荐
相关产品推荐

