set插入重复元素不会报错也不覆盖,insert()返回pair,second为false表示已存在;不可用operator[]访问,需用find()或count()判断存在性;自定义排序需满足严格弱序。

set 插入重复元素会怎样?
不会报错,也不会覆盖——set 本来就不允许重复。插入已存在的值时,insert() 返回一个 std::pair<iterator bool></iterator>,其中 second 是 false,first 指向原元素。别直接用 auto it = s.insert(x) 然后以为 it 一定指向新元素。
- 常见错误:用
set::insert()后没检查返回值的bool字段,误以为每次插入都成功新增了节点 - 场景:需要判断是否“首次出现”时(比如统计唯一请求 ID),必须读
it.second -
set内部是红黑树,插入/查找都是O(log n),重复插入只是多一次对数级比较,不慢但也不免费
为什么不能用 operator[] 访问 set 元素?
set 没有 operator[]。它不是数组或 map,没有“键索引值”的映射关系;它只维护有序、唯一的键本身。想查某个值是否存在,得用 find() 或 count()。
- 错误现象:
s[5]编译不过,报错类似no operator[] matches these operands - 正确做法:
if (s.find(5) != s.end()) { ... }或更简洁的if (s.count(5)) { ... } -
count()对set永远返回 0 或 1,性能和find()一样,选哪个纯看语义偏好
需要自定义排序时,传函数对象还是 lambda?
都可以,但 lambda 必须是类型稳定的——不能直接写在模板参数里(C++17 前不支持)。最稳妥是用命名函数对象或 std::greater<int></int> 这类标准仿函数。
- 错误写法:
set<int a int b return> b; }></int>—— 编译失败,lambda 类型不可默认构造且无法推导 - 可行写法:
set<int greater>></int>(升序改降序),或定义struct Cmp { bool operator()(int a, int b) const { return a > b; } };再用set<int cmp></int> - 注意:自定义比较必须满足严格弱序(strict weak ordering),比如不能写
a ,否则运行时可能崩溃或逻辑错乱
set 和 unordered_set 到底选哪个?
看你要不要“自动排序”。set 保证迭代器遍历是升序(按比较规则),unordered_set 不保证顺序、平均 O(1) 查找,但最坏 O(n),还额外占内存。
立即学习“C++免费学习笔记(深入)”;
- 场景匹配:
set适合需要遍历时有序(比如取 top-K、范围查询lower_bound)、或依赖稳定迭代顺序的逻辑 - 性能影响:
unordered_set插入快但可能 rehash,set内存更紧凑、无哈希冲突问题,且所有操作时间可预测 - 兼容性坑:如果代码里写了
for (auto it = s.begin(); it != s.end(); ++it)并依赖升序,换成unordered_set就行为突变,连测试都未必能立刻发现
set 时,最常被忽略的是它的“只读键”特性:你不能通过迭代器修改元素值,因为那会破坏排序结构。哪怕只是 *it = 10,编译器也会拦住——这不是限制,是设计必然。










