存储一组指针会导致未定义的行为吗?

时间:2013-02-26 10:40:17

标签: c++ memory-management c++11 set

请考虑以下代码:

#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

3 个答案:

答案 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

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