重现随机std :: set <t *>顺序

时间:2016-05-04 12:20:48

标签: c++ debugging pointers

我有一个测试随机失败,我怀疑由于std :: set中的对象顺序在指针值上排序。 但是,在我当前的exe上,测试总是通过。有没有办法可以&#34;混合&#34;指针创建所以我的集合中的对象顺序在两次运行之间是不同的?

换句话说,是&#34;排序顺序&#34; (p1&lt; p2)指针确定给定C ++代码,或者不同的编译或不同的运行可以有不同的排序顺序?

例如,在此代码中,添加&#34; p1b.reset(nullptr)&#34;在p1和p2之间创建将反转p1 / p2&#34;排序顺序&#34; 。有没有其他方法来影响这个顺序,而不更改源代码?

int main(void)
{
    std::unique_ptr< MyClass > p1b(new MyClass());

    //Lot of code, with memory allocated/deallocated

    std::unique_ptr< MyClass > p1(new MyClass());

    //p1b.reset(nullptr);

    //Lot of code, with memory allocated/deallocated

    std::unique_ptr< MyClass > p2(new MyClass());

    std::cout << "p1: " << p1.get() << std::endl;
    std::cout << "p2: " << p2.get() << std::endl;
}

给出:

p1: 0x171c030
p2: 0x171c050

使用&#34; p1b.reset(nullptr)&#34;评论说:

p1: 0x21f9030
p2: 0x21f9010

2 个答案:

答案 0 :(得分:2)

编辑2 :根据您的修改:https://stackoverflow.com/revisions/37027675/3

  

换句话说,是指针的“排序顺序”(p1 < p2)   确定性的给定C ++代码,或不同的编译或   不同的运行可以有不同的排序顺序吗?

是的,它们可以有不同的顺序,因为 - 当你在堆上分配时,内存分配器返回的指针地址的“连续顺序”是不可保证的,所以,是的,它可以随时改变。阅读答案的其余部分。

编辑1 :根据您的修改:https://stackoverflow.com/revisions/37027675/2

  

例如,在此代码中,在p1b.reset(nullptr)和之间添加p1   p2创建将反转p1 / p2订单。还有其他办法吗?   影响这个命令?

不,它不会“反转”创建顺序,您销毁p1并创建另一个对象(可能相等)并取代p1。阅读初步答案..

初步回答

  

有没有办法可以“混合”指针创作所以顺序   我的集合中的对象在两次运行之间有所不同吗?

有可能,你的内存分配器以连续的方式分配内存,所以如果你在一个线程程序中连续分配元素,它们可能会在一连串的内存地址中。但如果是关于绝对指针地址,由于Address space layout randomization

,它们可能会在程序的每次运行中处于“不同的”绝对偏移量

如果您希望连续元素的内存地址是随机的或按特定顺序,则必须以随机方式创建它,或者只是按照您想要的顺序创建...

对于一个随机的方式...... ...我的头脑:也许,为你想要创建的对象生成std::vector个索引;随机化(或随机)vector然后运行创建对象的向量元素。

我上面的回答是基于你所说的怀疑。但同样,我对此感到不安:

  

我有一个随机测试失败,我怀疑是因为一个对象的顺序   std :: set在指针值上排序。但是,在我当前的exe上,   测试总是通过

检查Undefined Behaviors并通过代码运行内存工具和静态分析器。

答案 1 :(得分:-2)

在堆上分配对象的顺序完全取决于您。顺便说一句,你确实记得std::set当被​​销毁时只调用它的内容析构函数,如果是指针则意味着指针根本就​​不存在,而它们指向的对象仍然存在于堆中并且可能已成为悬空引用,对吧?如果您在std容器中存储普通指针,请不要忘记手动delete