我使用stl set
容器类来存储指向对象的指针。在读取stl集时,对于程序的不同运行,由于对对象的内存(地址)的动态分配,对象的顺序会发生变化。
假设物体是A,B,C,它们在首次运行时的地址是10,16,12。因此,当我将这些对象插入 set 并检索它们时,我将得到输出为A C B(b'caz 10&lt; 12&lt; 16)。现在,如果在下一次运行中分配的地址是14,10,8,我将得到输出为C B A(8 <10 <14)。
有什么方法可以按顺序获得输出?
重载比较器(自定义比较器)可以解决问题,但在这种情况下,我必须将其作为模板参数传递,这导致在许多地方修改代码。有没有办法避免修改我的代码,仍然可以编写客户比较器?
答案 0 :(得分:3)
不应按指针的值进行排序,而应该通过指向的值传递一个比较对象排序:
struct deref_compare {
template <typename T>
bool operator()(T const* o0, T const* o1) const {
return *o0 < *o1;
}
};
std::set<int*, deref_compare> s;
// use s as before
如果您无法更改std::set<int*>
的声明,您可以技术专门化std::less<int*>
做一些不同的事情,但除非您不允许专门涉及用户定义的类型:
namespace std
{
template <>
class less<int*> {
public:
bool operator()(int const* o0, int const* o1) const {
return *o0 < *o1;
}
};
}
请注意,在不涉及用户定义类型的情况下专门化任何标准类模板会导致未定义的行为:我建议不要专门化std::less<int*>
。问题是它可能影响其他代码,例如,在标准C ++库中。 C ++标准的相关部分是17.6.4.2.1 [namespace.std]第1段:
如果C ++程序向名称空间
std
或名称空间std
中的名称空间添加声明或定义,则它是未定义的,除非另有说明。只有当声明取决于用户定义的类型且专业化符合原始模板的标准库要求且未明确禁止时,程序才可以将任何标准库模板的模板特化添加到命名空间std
。
答案 1 :(得分:2)
由于std::set
中强加的订单是通过元素的自然排序来管理的,因此如果您需要特定订单,则需要一个不会改变每个特定运行的特定标准。这是因为指针的自然顺序只涉及地址本身的值。
这意味着您需要通过特定的比较运算符来为它们提供一致的顺序,例如:
struct my_order {
bool operator() (const Object* lhs, const Object* rhs) const {
// return consistent value for same pair of lhs and rhs
}
set<Object*, my_order> mySet;
答案 2 :(得分:2)