应避免直接将每行字符串塞入std::set,因其不自动trim、无法区分空行与空白行、且会把"abc"和"abc "视为不同字符串;正确做法是先用find_first_not_of/find_last_not_of手动trim,再判空、插入。

为什么用 std::set 做行级去重容易出错
直接把每行字符串塞进 std::set 看似合理,但实际会忽略换行符处理、空行判定、以及输入边界——比如 std::getline 读到的行末不带 \n,而文件末尾可能无换行,导致两行内容被拼成一行;更常见的是把空行("")和空白行("\t \n")混为一谈。一旦没 trim 就插入,std::set 会把 "abc" 和 "abc " 当作不同字符串存下来。
如何正确读取并清洗每一行再插入 std::set
核心是:读、trim、判空、插。不要依赖 std::string 默认构造或隐式转换。
- 用
std::getline逐行读,它自动剥离\n(不保留) - 手动 trim 左右空白:用
find_first_not_of和find_last_not_of,别用boost::trim或 C++20 的std::ranges::trim(兼容性差) - trim 后检查是否为空:用
line.empty(),不是line == ""(等价但可读性差) - 只对非空行调用
my_set.insert(trimmed_line)
示例关键片段:
std::set<:string> lines;
std::string line;
while (std::getline(std::cin, line)) {
auto start = line.find_first_not_of(" \t\r\n");
auto end = line.find_last_not_of(" \t\r\n");
if (start == std::string::npos) continue; // 全空白
std::string trimmed = line.substr(start, end - start + 1);
lines.insert(trimmed);
}</:string>
std::set vs std::unordered_set:性能差别在哪
行级去重若只关心“是否重复”,不依赖字典序输出,std::unordered_set 平均 O(1) 插入比 std::set 的 O(log n) 更快,尤其当行数超万时差异明显。但要注意:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
std::unordered_set<:string></:string>默认哈希函数对长字符串可能碰撞略高,不过日常文本影响不大 - 如果后续要按字母序输出去重结果,
std::set省掉一次std::sort;否则优先选unordered_set - 内存占用:两者都存一份字符串副本,
unordered_set额外有桶数组开销,但通常可接受
输出时保留原始顺序还是排序后输出?
std::set 天然排序,但“行级去重”常要求保持首次出现顺序——这时候 std::set 本身无法满足。必须额外用 std::vector 记录顺序,或改用 std::unordered_set + std::vector 组合:
- 用
std::unordered_set判重 - 用
std::vector<:string></:string>按插入顺序存唯一行 - 每次
getline后先查 set,未存在则 push_back 到 vector 并 insert 到 set
这个组合才是真实场景下“快速 + 保序”的解法。单纯依赖 std::set 的插入逻辑,本质是放弃顺序保证。
真正麻烦的不是怎么塞进容器,而是定义清楚“什么是同一行”:是否忽略首尾空格?是否区分大小写?这些判断必须在插入前做完,而不是靠容器行为兜底。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










