为C ++ STL队列预分配空间

时间:2009-08-20 04:41:57

标签: c++ performance memory stl queue

我正在使用队列编写基数排序算法,我希望在开始向队列添加内容之前让STL队列分配空间,这样我就可以避免不断的动态调整大小操作。

即使这不存在,我想要一些具有......的效果的东西。

queue<int> qs(N);
for(int i=0;i<N;++i)
  qs.push(rand());

以这种方式在循环期间不会动态分配任何内存。

有问题的实际代码......

void radix_sort()
{
// Biggest number?
int max=-1;
for(int i=0;i<N;++i)
    if(a[i]>max)
        max = a[i];

// How many digits in it
int maxdigits=1;
while(max /= 10) maxdigits++;

// Create some buckets.
deque<int> b[10];
for(int i=0;i<10;++i)
    b[i] = deque<int>(N);

int div=1;
// Radix Sort by digits
for(int d=1;d<=maxdigits;++d)
{
    if(d>1)
        div*=10;

    // Queue
    for(int i=0;i<N;++i)
        b[ (a[i]/div) % 10 ].push_front(a[i]);

    // Dequeue
    int k=0;    
    for(int q=0;q<10;++q)
        while(b[q].size() > 0)
        {
            a[k++] = b[q].back();
            b[q].pop_back();
        }
}
}

6 个答案:

答案 0 :(得分:26)

这可能不是问题。无论如何Deque分配,所以你可能只会重新分配几次。你确定这是一个瓶颈吗?

无论如何,标准没有提供`queue'容器的访问器,因为这会破坏封装的目的。

如果你真的很担心,游泳池分配。这意味着预先预先分配内存,所以当容器请求内存时,它已经存在。我不能真的去讨论分配器和亲属,这对于一个SO答案来说太过分了,但是查找allocators on Google

基本上,你可以告诉容器从哪里获取内存。通常,这是默认的分配器,它使用new和delete。

Boost提供pool allocator,它会是这样的:

#include <list>
#include <queue>

// pool
#include <boost/pool/pool_alloc.hpp>

// helpful typedef's
typedef boost::fast_pool_allocator<int> BoostIntAllocator;
typedef boost::singleton_pool<boost::fast_pool_allocator_tag, sizeof(int)> BoostIntAllocatorPool;

int main(void)
{
    // specify the list as the underlying container, and inside of that,
    // specify fast_pool_allocator as the allocator. by default, it preallocates
    // 32 elements.
    std::queue<int, std::list<int, BoostIntAllocator > > q;

    /* No memory allocations take place below this comment */

    for (int i = 0; i < 31; ++i)
    {
        q.push(i);
    }

    /* End no allocation */

    // normally, the memory used by the singleton will
    // not be free'd until after the program is complete, 
    // but we can purge the memory manually, if desired:
    BoostIntAllocatorPool::purge_memory();
};

池预先分配内存,因此在push() / pop()期间不会进行实际的内存分配。

我使用list代替deque,因为它更简单。通常情况下,deque is superior to a list,但有一个分配器,使deque有利的事情,如缓存性能和分配成本,不再存在。因此,list更易于使用。

您还可以使用circular buffer,例如:

#include <queue>

// ring
#include <boost/circular_buffer.hpp>

int main(void)
{
    // use a circular buffer as the container. no allocations take place,
    // but be sure not to overflow it. this will allocate room for 32 elements.
    std::queue<int, boost::circular_buffer<int> > q(boost::circular_buffer<int>(32));

    /* No memory allocations take place below this comment */

    for (int i = 0; i < 31; ++i)
    {
        q.push(i);
    }

    /* End no allocation */
};

答案 1 :(得分:4)

您可以尝试使用std :: deque而不是......

答案 2 :(得分:3)

如果您使用其中一个结构来组成支持“保留”函数调用的队列,那么您应该很好。如果此数据结构不支持您的需求,您可能需要查找另一个。

话虽如此,你确定这里存在性能问题吗?

雅各

答案 3 :(得分:2)

听起来你需要一个带有reserve()方法的数据结构,以及来自两端的高效“推”和“弹出”操作。如何将环形缓冲区包裹在std :: vector中?您可以在构造函数中保留()所需的空间,然后在实现中维护“前”和“结束”索引,将公共接口中的“push”和“pop”操作转换为底层std上的O(1)操作::矢量。

答案 4 :(得分:1)

而不是队列,如何使用列表代替?

答案 5 :(得分:1)