请考虑以下代码:
#include <iostream>
int main(int argc, char ** argv) {
std::set<int*> ints;
for (int i = 0; i < 10; i ++) {
int * k = new int(i);
ints.insert(k);
}
for (auto i : ints) {
// some order-sensitive operations, for example:
std::cout << (*i) << " ";
}
return 0;
}
第二个循环对从集合中取出元素的顺序敏感。在程序的不同运行中,这种程序的执行结果是否可能不同?
据我所知,std::set
在内部对元素进行排序。由于内存中的分配不一定具有增加的地址,因此(尽管不太可能)该程序的输出不会是0 1 2 3 4 5 6 7 8 9
?
答案 0 :(得分:5)
是的,它们可能不同,但不会是因为UB。
这里定义的实现有两件事:
std::less<int*>
执行排序的方式(虽然在大多数实现中您会看到“自然”排序)operator new
返回的地址每次都可能相同或不同。这很可能会因您的实现使用的分配器而异,并且两种方式(确定性的和看似随机的)都是在野外看到的。 (请注意,当您通过例如valgrind运行程序时,顺序可能仍然始终相同,但与本机运行时不同)。所以不要依赖于你感兴趣的任何特定顺序。
答案 1 :(得分:2)
在标准意义上,它不是“未定义的行为”(任何都可能发生)。
但是,绝对没有指定在分配内存时将获得的指针地址。标准没有说明免费商店的组织方式,也没有说明不同分配的地址顺序。
答案 2 :(得分:0)
使用手册,Luke。
std::set documentation in MSDN
STL集是:
(...)
已排序,因为其元素按照指定的比较函数按容器内的键值排序。
指针只是整数,因此这些变量将按其地址排序。内存管理器可以在非常不同的地方分配这些变量,因此您无法保证它们的顺序(就其值而言)将被保留。
但是,似乎您可以提供自己的比较功能:
std::set::set() documentation on MSDN
然后,您可以按照最适合您的方式对集合的元素进行排序。