std :: pair <int,int> vs struct with two int's

Eta*_*tan 29 c++ performance std-pair

在ACM示例中,我必须构建一个用于动态编程的大表.我不得不在每个单元格中存储两个整数,所以我决定去找一个std::pair<int, int>.但是,分配大量的数组需要1.5秒:

std::pair<int, int> table[1001][1001];
Run Code Online (Sandbox Code Playgroud)

之后,我将此代码更改为

struct Cell {
    int first;
    int second;
}

Cell table[1001][1001];
Run Code Online (Sandbox Code Playgroud)

并且分配花了0秒.

是什么解释了这个巨大的时间差异?

sha*_*oth 35

std::pair<int, int>::pair()构造函数使用默认值初始化字段(如果是,则为零int),而struct Cell不是(因为您只有一个自动生成的默认构造函数,不执行任何操作).

初始化需要写入每个字段,这需要大量相对耗时的存储器访问.有了struct Cell什么都不做,而不是和什么都不做是有点快.

  • 不,问题是函数调用构造函数.如果你的数组是全局的,那么无论如何它都被初始化为零.可能编译器没有优化构造函数调用. (7认同)
  • 将大约8 MB设置为零需要1.5秒吗? (4认同)
  • 你需要调用构造函数,找到内存,设置它等等......它不仅仅是通过memset将N位的连续内存设置为0. (2认同)
  • @Lemurik:我不相信.所有`pair`构造函数都委托给它(POD)成员的构造函数.编译器可以(和恕我直言,*应该*)识别这一点,忽略构造函数调用并简单地将内存清零.这样做的分析肯定不难吗? (2认同)

And*_*dge 25

到目前为止,答案并没有解释问题的全部重要性.

正如尖锐的指出,对解决方案将值初始化为零.正如Lemurik所指出的那样,对解决方案不仅仅是初始化一个连续的内存块,而是为表中的每个元素调用对构造函数.然而,即使这样也不会占用1.5秒.还有其他事情正在发生.

这是我的逻辑:

假设你在一台古老的机器上,比如以1.33ghz运行,那么1.5秒是2e9个时钟周期.你有2e6对来构造,所以每对构造函数都需要1000个循环.调用仅将两个整数设置为零的构造函数不需要1000个周期.我看不出缓存未命中会如何花费这么长时间.如果数量小于100个周期,我会相信它.

我认为看到所有这些CPU周期的其他部分将会很有趣.我使用了我能找到的最古老的C++编译器来查看是否可以达到所需的浪费水平.那个编译器是VC++ v6.在调试模式下,它做了我不理解的事情.它有一个大循环,为表中的每个项调用对构造函数 - 足够公平.该构造函数将两个值设置为零 - 足够公平.但就在这之前,它将68字节区域中的所有字节设置为0xcc.那个区域就在大桌子开始之前.然后用0x28F61200覆盖该区域的最后一个元素.对构造函数的每次调用都会重复此操作.据推测,这是编译器的某种书籍保存,因此它知道在运行时检查指针错误时初始化了哪些区域.我很想知道这是为了什么.

无论如何,这将解释额外时间的去向.显然,另一个编译器可能不是这么糟糕.当然,优化的发布版本也不会.

  • 这不是VC++ V6的错误.在调试模式下,所有VC编译器都会将堆栈上分配的所有字节初始化为陷阱值(默认为0xCC),并且所有分配的堆内存将同样初始化为0xCD.目的有两个:导致任何正在操作的代码(零假设)未初始化的变量大声失败,并让您在内存调试器中看到未初始化的堆栈.您看到的最后一个值是用于检测堆栈溢出(.com*giggle*)的"堆栈金丝雀值". (4认同)