2009-09-22 69 views
33

我的代码std :: vector reserve()和push_back()比resize()和数组索引快,为什么?

void ConvertToFloat(const std::vector<short>& audioBlock, 
        std::vector<float>& out) 
{ 
    const float rcpShortMax = 1.0f/(float)SHRT_MAX; 
    out.resize(audioBlock.size()); 
    for(size_t i = 0; i < audioBlock.size(); i++) 
    { 
     out[i] = (float)audioBlock[i] * rcpShortMax; 
    } 
} 

块上做一个快速的性能测试,我很高兴与加速比原先很天真的实现它只需在1毫秒处理65536个音频采样。

但只是为了好玩我尝试以下

void ConvertToFloat(const std::vector<short>& audioBlock, 
        std::vector<float>& out) 
{ 
    const float rcpShortMax = 1.0f/(float)SHRT_MAX; 
    out.reserve(audioBlock.size()); 
    for(size_t i = 0; i < audioBlock.size(); i++) 
    { 
     out.push_back((float)audioBlock[i] * rcpShortMax); 
    } 
} 

现在我完全可以预料这给完全相同的性能,因为原代码。然而突然间,循环现在需要900usec(即比其他实现快100倍)。

任何人都可以解释为什么这会提供更好的性能? resize()初始化新分配的向量,其中保留只分配但不构造?这是我能想到的唯一的事情。

PS在单核2Ghz AMD Turion 64 ML-37上进行了测试。

+0

例行检查时,编译代码时使用的是释放而不是调试设置? – Laserallan 2009-09-22 17:15:25

+0

hehehe,是的,我正在使用发布。这是关于帮助编译器帮助我的更多问题:) – Goz 2009-09-22 18:25:52

回答

52

是否调整大小初始化新分配的矢量,其中保留只分配但不构造?

是的。

+0

SGI的STL参考文献解释了调整大小“在最后插入或擦除元素”,而保留只是执行内存分配。 http://www.sgi.com/tech/stl/Vector.html – user7116 2009-09-22 17:05:37

+0

这是如何工作的? malloc的? – pyon 2009-09-22 17:06:42

+0

它将使用分配器为矢量设置的任何值。 – user7116 2009-09-22 17:09:30

1
out.resize(audioBlock.size()); 

由于out的大小(= 0)低于audioBlock.size()较小,被创建并附加到out的端部的附加元件。这通过调用它们的默认构造函数来创建新的元素。

保留只分配内存。

3

第一个代码写入out[i],归结为begin() + i(即加法)。第二个代码使用push_back,它可能立即写入相当于end()的已知指针(即不添加)。通过使用迭代器而不是整数索引,您可以使第一次运行速度与第二次运行速度一样快。

编辑:也澄清一些其他意见:载体含有浮标,构建浮子实际上是一个无操作(以同样的方式,宣布“浮动的f;”不发射码,只告诉编译器为堆栈上的浮点节省空间)。所以我认为对于浮动矢量而言,resize()reserve()之间的任何性能差异与建筑无关。

+3

对不起,但你的建设点是不真实的。 float f = 0.0f;显然比“float f;”慢。后者是前者不是前者。 – Goz 2009-09-22 17:16:40

+0

哦,公平点,不知道构造一个赋值为0的浮点数。向量在调整大小时将T()赋值给每个元素,即float(),该值为0.仍然使用迭代器代替整数索引可能会更快。 – AshleysBrain 2009-09-22 17:28:02

3

调整尺寸()

修改所述容器,以便它具有恰好n个元素,在插入端部元件,或者如果需要,在从结束擦除元件。如果插入了任何元素,则它们是t的副本。如果n > a.size(),这个表达式相当于a.insert(a.end(), n - size(), t)。如果是n < a.size(),则相当于a.erase(a.begin() + n, a.end())

预订()

如果n小于或等于capacity(),此调用将不起作用。否则,它是分配额外内存的请求。如果请求成功,则capacity()大于或等于n;否则,capacity()不变。无论哪种情况,size()都不变。

如果超过capacity() - size()元素插入向量中,内存将自动重新分配。重新分配不会改变size(),也不会更改矢量的任何元素的值。但是,它确实增加了capacity()

保留导致手动重新分配。使用reserve()的主要原因是效率:如果您知道矢量最终必须增长的容量,那么一次分配内存通常更有效,而不是依赖于自动重新分配方案。

相关问题