C++中使用set容器的标准比较器是什么?含指针比较疑惑
C++ set容器的标准比较器规则说明
默认标准比较器的定义
- 从C++标准对
std::set的模板定义来看,其第三个模板参数为比较器类型,默认采用std::less<T>作为标准比较器。 std::less<T>的核心比较逻辑是对存储的元素对象调用类型自带的<运算符,基于元素的自身内容值实现严格弱序判定,整个过程不会参考元素自身在内存中的存储地址(也就是元素变量本身所占内存块的首地址)。
常见认知误区澄清
疑惑本质是混淆了“元素自身的内存位置”和“元素的存储值”两个概念,所有set的比较逻辑自始至终都不会读取元素变量本身所占内存块的首地址做对比,永远围绕元素的存储值展开:
- 当set存储非指针类型的普通对象时
比较操作完全围绕对象的内容值展开。哪怕两个同类型对象在内存中的存储位置不同,只要它们的内容满足“互相<的结果都为false”,set就会判定两个元素等价,不会因为两个对象的内存地址不同就将其视为不同元素。 - 当set存储指针类型的元素时
std::less针对原始指针类型的特化实现,比较的是指针变量自身存储的地址值(也就是指针这种类型对应的“值”),全程不会对指针做解引用,更不会比较指针指向的对象内容。这里看起来是在比较地址,本质是因为指针类型的存储值本来就是内存地址,和比较器专门拿内存地址做判断是完全不同的逻辑。
用具体场景做直观对照:
假设栈上定义两个int变量:int a = 10; int b = 20;,其中a的内存地址为0x7ffd0001,b的内存地址为0x7ffd0002
- 存入
std::set<int>时,比较逻辑只会判断10 < 20的数值大小,完全不会读取两个变量的所在地址做对比- 存入
std::set<int*>时,比较逻辑只会对比两个元素(也就是&a、&b这两个指针值)存储的地址0x7ffd0001和0x7ffd0002的大小,不会解引用指针去判断10和20的数值关系
指针类场景的自定义比较逻辑
如果需要让存储指针的set按照指针指向的对象内容做排序去重,不能依赖默认的std::less,需要传入自定义的比较器实现解引用后的值比较,例如:
// 自定义比较逻辑:解引用指针后比较指向的内容 auto cmp_ptr = [](const int* lhs, const int* rhs) { return *lhs < *rhs; }; // 传入自定义比较器构造set std::set<int*, decltype(cmp_ptr)> ptr_set(cmp_ptr);
内容的提问来源于stack exchange,提问作者Jacob
相关产品推荐
相关产品推荐

