影响指针集合排序的因素(具体示例)
What affects ordering in my set of pointers (specific example)
在下面的测试代码中,指针显然是按照集合中的地址排序的,如打印输出所示。在不改变对象插入顺序的情况下,什么可以改变集合中的顺序,使id不按顺序打印?
谁能通过修改这段代码来展示一个例子?
#include <iostream>
#include <set>
class Object {
int id;
public:
void setId (int i) {id = i;}
int getId() {return id;}
};
int main ()
{
std::set<Object*> myset1;
std::set<Object*> myset2;
std::set<Object*>::iterator it;
Object *obj;
for (int i=1; i<=5; ++i){
obj = new Object();
obj->setId(i);
myset1.insert(obj);
}
for (int i=1; i<=5; ++i){
obj = new Object();
obj->setId(i);
myset2.insert(obj);
}
std::cout << "myset1 contains:";
for (it=myset1.begin(); it!=myset1.end(); ++it)
std::cout << ' ' << (*it)->getId() << "(" << (long long)*it << ")";
std::cout << 'n';
std::cout << "myset2 contains:";
for (it=myset2.begin(); it!=myset2.end(); ++it)
std::cout << ' ' << (*it)->getId() << "(" << (long long)*it << ")";
std::cout << 'n';
return 0;
}
输出:myset1 contains: 1(24842256) 2(24842336) 3(24842416) 4(24842496) 5(24842576)
myset2 contains: 1(24842656) 2(24842736) 3(24842816) 4(24842896) 5(24842976)
您的问题有点模糊,因为不清楚您是在为未说明的问题寻求比较器更改解决方案,还是只是想知道相同的比较器和相同的插入顺序是否有可能不生成您所看到的排序。大多数其他答案似乎都是基于前者;
std::set<>
容器默认使用std::less<>
作为比较器。对于任何指针类型,std::less<>
提供了基于总内存排序的专门化(如您所见)。
你完全任由内存分配器摆布。例如,考虑对第一个循环进行以下代码更改:
char *tmp = new char[sizeof(Object)];
for (int i=1; i<=5; ++i){
obj = new Object();
obj->setId(i);
myset1.insert(obj);
if (i == 3)
delete [] tmp; // open the hole up after the third insertion
}
在我的设备上(OS X 10.10.5),它给出以下输出:
myset1 contains: 4(4296037184) 1(4296037200) 2(4296037264) 3(4296037328) 5(4296037440)
myset2 contains: 1(4296037504) 2(4296037568) 3(4296037632) 4(4296037696) 5(4296037760)
我可以推测是什么引起的。这个初始临时分配一旦被释放,就会在堆管理器的自由链中添加一个空闲块,这个块的大小(并非巧合)正好适合循环中消耗的下一个分配(第四个)。
不知道这是不是你想要的,但最重要的是,你的代码确实完全受内存管理器的支配,它决定了对象占用的地址,从而决定了它们在集合中的顺序。
默认情况下,set中的元素按指针排序。不能保证以什么顺序获得这些指针(是的,它们有可能是顺序的,但没有这样的保证)。如果你想要稳定的顺序,你需要添加比较函子。另一种方法是创建vector并使用Object指针指向vector的元素,它们将按顺序排列:
struct ObjectLess : public std::binary_function<Object, Object, bool> {
bool operator()(const Object* lhs, const Object* rhs) const
{
return lhs->getId() < rhs->getId();
}
};
请注意,我已将const
添加到getId
:
#include <iostream>
#include <set>
class Object {
int id;
public:
void setId (int i) {id = i;}
int getId() const {return id;}
};
struct ObjectLess : public std::binary_function<Object, Object, bool> {
bool operator()(const Object* lhs, const Object* rhs) const
{
return lhs->getId() < rhs->getId();
}
};
int main ()
{
std::set<Object*, ObjectLess> myset1;
std::set<Object*, ObjectLess> myset2;
std::set<Object*, ObjectLess>::iterator it;
Object *obj;
for (int i=1; i<=5; ++i){
obj = new Object();
obj->setId(i);
myset1.insert(obj);
}
for (int i=1; i<=5; ++i){
obj = new Object();
obj->setId(i);
myset2.insert(obj);
}
std::cout << "myset1 contains:";
for (it=myset1.begin(); it!=myset1.end(); ++it)
std::cout << ' ' << (*it)->getId() << "(" << (long long)*it << ")";
std::cout << 'n';
std::cout << "myset2 contains:";
for (it=myset2.begin(); it!=myset2.end(); ++it)
std::cout << ' ' << (*it)->getId() << "(" << (long long)*it << ")";
std::cout << 'n';
return 0;
}
输出:myset1 contains: 1(105690555281392) 2(105690555281360) 3(105690555281328) 4(105690555281296) 5(105690555281264)
myset2 contains: 1(105690555281232) 2(105690555281200) 3(105690555281168) 4(105690555281136) 5(105690555281104)
您不能更改std::set
的默认行为,除非为它提供比较器,并在其中定义您自己的比较逻辑来控制顺序,例如:
struct MyCom {
bool operator()(Object* o1, Object* o2) const { return o2->getId() < o1->getId(); }
};
和
std::set<Object*, MyCom> myset2;
现在myset2
中的元素将按照Object::id
的desc顺序排序:
生活myset2包含:5(144501624)4(144501584)3(144501544)2(144501504)1(144501464)
- 互斥指针的集合
- MPI 集合通信中的指针分配
- 保留计时器集合(对象与指针)的最佳方法
- 如何让集合 in C++过滤掉指向相同值的不同指针
- 集合中的智能指针多态性
- 重载指向集合的指针的开始/结束是否是个好主意
- C++基类指针、集合类
- Boost:当缺少类型时,如何通过基指针序列化/反序列化泛型类型集合
- 使用指针在恒定时间内从集合中删除
- 无法将对象上的指针添加到集合
- 如何保留指向插入到集合中然后推送到向量中的对象的指针
- C++ 创建指向两个相关矢量集合中的对象的指针集合
- 将指向派生类实例的指针集合视为父类
- 管理指向派生对象的指针集合的最佳方式
- 指针集合和添加对象
- C++指针集合类,便于通信
- 将指针传递到集合向量C++/cx
- 更好的std::在指针集合上查找,并将取消引用的值与常量引用值进行比较
- 当返回一个集合指针时,客户端如何知道它是否需要销毁它?
- 指针的集合.复制构造函数问题