1

考虑以下代码:

#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

4

3 回答 3

5

是的,它们可能不同,但这不会是因为 UB。

这里定义了两件事:

  • 排序方式std::less<int*>(尽管在大多数实现中您会看到“自然”排序)
  • operator new每次返回的地址可能相同也可能不同。这很可能会因您的实现使用的分配器而异,并且两种方式(确定性和看似随机)都已在野外看到。(请注意,当您通过例如 valgrind 运行程序时,顺序可能仍然始终相同,但与本机运行时不同)。

所以不要依赖于你感兴趣的任何特定顺序。

于 2013-02-26T10:46:27.913 回答
2

这不是标准意义上的“未定义行为”(任何事情都可能发生)。

但是,绝对未指定分配内存时将获得的指针地址。该标准没有说明免费存储的组织方式或不同分配的地址顺序。

于 2013-02-26T10:45:50.210 回答
0

使用手册,卢克。

MSDN 中的 std::set 文档

STL 集是:

(...)

排序,因为它的元素是按照指定的比较函数在容器内按键值排序的。

指针只是整数,所以这些变量将按它们的地址排序。内存管理器可以将这些变量分配在非常不同的位置,因此您无法保证它们的顺序(就它们的值而言)将保持不变。

但是,您似乎可以提供自己的比较功能:

MSDN 上的 std::set::set() 文档

然后,您可以以最适合您的方式对 set 的元素进行排序。

于 2013-02-26T10:45:41.113 回答