我遇到了STL队列推送中的一个行为,我不太明白。
基本上,我有两个struct
structA{
string a;
}
structB{
char b[256];
}
structA st1;
structB st2;
...assign a 256 characters string to both st1 and st2...
queue<structA> q1;
queue<structB> q2;
for(int i=0 ; i< 10000; i++){
q1.push(st1);
}
for(int i=0 ; i< 10000; i++){
q2.push(st2);
}
我意识到使用char结构的队列与字符串结构相比,在推送结构时会使用更长的时间(如5X)。在检查单个推送时,我意识到char struct push性能在这里和那里有相当多的尖峰(范围从2X到10X)。这是什么原因?
感谢。
答案 0 :(得分:4)
每次将st1或st2推送到队列时,实际上是在推送它的副本(不是引用或指针)。成本差异在于复制数据。在structB
中,您必须每次复制完整的256个字节。在structA
中,您只复制字符串实例,该实例最有可能具有写时复制语义,因此在修改其中一个之前,它们将共享对基础字符串数据的相同引用。
答案 1 :(得分:1)
您的C ++实现可能使用写时复制字符串实现,这意味着字符串副本不会真正复制字符串(而是链接回副本),并且只在写入时复制字符串“for real”它。
要测试是否是这种情况,请在q1.push(st1)
行之后将其放入循环中:
++st1.a[0];
再一次。
显然,字符数组没有写入时复制行为,并且每次要求复制时都会“真实地”复制。
答案 2 :(得分:0)
字符数组大于空字符串 - 峰值可能与向量增长所需的重新分配有关,因为它使用了更大的内存量。
如果字符串不为空,那么无论如何都会写入写操作,因此您需要针对内存使用交换一些锁定时间/引用计数器递增等:更快的是系统相关的。
答案 3 :(得分:0)
原因很可能是由于:
1)动态分配内存以保存每个字符串内的字符数据
2)可能,但不太可能调整后退队列的deque页面缓冲区的大小。
答案 4 :(得分:0)
std :: queue是另一个容器(实现front,back,push_back和pop_front)的适配器,除非你指定要调整哪个容器,它将使用std :: deque。 Deque在后台执行了一些块分配魔法应该提供类似于vector的大小调整,但是由于它管理多个不连续的块而且每次调整大小时都不需要复制所有内容,因此性能更好。无论如何,这是一个猜测,但我会说这是原因。
由于为所有这些数组腾出空间,字节数组结构更频繁地看到命中,我打赌在更长的规模上字符串结构也会产生尖峰,现在它只是更小,因为字符串可能保持对下属的引用字符存储直到某些东西改变它。
现在您有机会熟悉您选择的探查器,并确定无疑!消防valgrind( - callgrind)或您的平台支持的任何分析器,并确切地查看哪些呼叫正在使用时间和地点。