我在理解std::set
(或std::map
等)如何识别唯一密钥方面遇到问题。我想做的是将一个结构对象包装在boost::shared_ptr
中,然后将该共享指针存储在std::set
容器中:
假设结构是一种颜色:
struct Color {
float r;
float g;
float b;
};
然后在另一个类中定义容器和比较函数对象:
class AnotherClass {
typedef boost::shared_ptr<Color> ColorPtr;
public:
struct ColorCompare {
bool operator()(const ColorPtr &a, const ColorPtr &b) const {
return (a->r > b->r) && (a->g > b->g) && (a->b > b->b);
}
};
private:
// Container definition
std::set<ColorPtr, ColorCompare> colors;
};
上面的代码无法根据封装的Color
结构唯一标识shared_ptr
对象。我一直认为std::set
容器会在两个对象上运行一个比较函数,如果它们都不大于或小于另一个,它会假设它们相等。注意,我不能使用默认的shared_ptr::operator<()
和less<...>
,因为该实现是基于指针地址的。
我错过了什么?
p.s.我在shared_ptr
中包装颜色,因为我需要知道它们在某个点的引用计数(并删除引用计数为1的颜色,也就是说,仅由std::set
容器本身引用)。有没有更好的方法可以得到同样的结果?
比较需要是严格的弱排序,而您的不是。(例如,(1,0,0)和(0,1,0)是如何排序的?)这样做:
return (a->r > b->r) ||
((a->r == b->r) && (a->g > b->g)) ||
((a->r == b->r) && (a->g == b->g) && (a->b > b->b) );
这是元素元组上的标准字典排序。
请注意,您通常会编写!(b->r > a->r)
而不是a->r == b->r
,这样就不会引入对兼容的相等运算符的依赖,尽管在这个简单的浮点情况下,我们可以。
顺便说一下,您不需要struct
,只需声明一个static bool ColorCompare(...);
函数即可。另一种选择是直接在struct Color
中定义一个operator<
,使所有内容都是自包含的(因此您只需要一个用于(智能)指针的通用去引用比较器)。