什么是QList的最大尺寸?

时间:2014-11-24 23:39:44

标签: c++ qt qt4 qtcore qlist

是否有人遇到过QList的最大尺寸?

我有一个指向我的对象的指针的QList,并且发现当它到达268,435,455项(它正好是28位)时它会默默地抛出一个错误。我原以为它至少有一个31位的最大大小(减去一位因为size()返回有符号整数),或者我的64位计算机上最大大小为63位,但事实并非如此。我在最小的例子中通过在计数循环中执行QList<void*> mylist; mylist.append(0);来确认这一点。

要重申这个问题,QList的实际最大大小是多少?如果它实际上不是2 ^ 32-1那么为什么呢?有解决方法吗?

我正在为MSVC2010运行Qt 4.8.5的Windows 64位版本。

4 个答案:

答案 0 :(得分:2)

  

有没有人遇到过QList的最大尺寸?我有一个指向我的对象的指针的QList,并且发现当它到达268,435,455项(它正好是28位)时它会默默地抛出一个错误。我原以为它至少有一个31位的最大大小(减去一位因为size()返回有符号整数),或者我的64位计算机上最大大小为63位,但事实并非如此。

存储在int中的理论最大正数是2 ^ 31 - 1.指针的大小是4个字节(对于32位机器),因此最大可能的数量是2 ^ 29 - 1.将数据附加到容器将增加碎片堆内存,所以有可能你只能分配一半的可能内存。请尝试使用reserve()或resize()。

此外,Win32对内存分配有一些限制。因此,在没有特殊选项的情况下编译的应用程序不能分配超过此限制(1G或2G)。

你确定这个巨大的容器吗?优化应用程序更好吗?

答案 1 :(得分:2)

虽然其他答案在解释问题方面做出了有益的尝试,但实际上没有人回答问题或错过了重点。感谢大家帮助我追踪这个问题。

正如Ali Mofrad所提到的,当QList无法在QList::append(MyObject*)调用中分配额外空间时,抛出的错误是std::bad_alloc错误。这是Qt源代码中出现的地方:

qlist.cpp: line 62:
static int grow(int size)         //size = 268435456
{
    //this is the problem line
    volatile int x = qAllocMore(size * sizeof(void *), QListData::DataHeaderSize) / sizeof(void *);
    return x;                     //x = -2147483648
}

qlist.cpp: line 231:
void **QListData::append(int n)   //n = 1
{
    Q_ASSERT(d->ref == 1);
    int e = d->end;
    if (e + n > d->alloc) {
        int b = d->begin;
        if (b - n >= 2 * d->alloc / 3) {
            //...
       } else {
            realloc(grow(d->alloc + n));    //<-- grow() is called here
        }
    }
    d->end = e + n;
    return d->array + e;
}

grow()中,请求的新大小(268,435,456)乘以sizeof(void*)(8)以计算新内存块的大小以适应不断增长的QList。问题是,268435456 * 8等于+2,147,483,648(如果它是无符号的int32),或者-2,147,483,648用于有符号的int32,这是我在操作系统上从grow()返回的内容。因此,当在QListData::realloc(int)中调用std :: realloc()时,我们会尝试增长到负值。

这里的解决方法,正如ddriver建议的那样,是使用QList::reserve()预先分配空间,防止我的QList不得不增长。

简而言之,除非您预先分配,否则QList的最大大小为2 ^ 28-1项,在这种情况下,最大大小确实是2 ^ 31-1。

答案 2 :(得分:1)

QList将其元素存储在void *数组中。

因此,一个包含2个 28 项的列表,其中每个项都是void *,在32位机器上长度为2 30 字节,在64位机器上有2个 31 字节。我怀疑你能不能请求如此大量的连续记忆。

为什么分配这么大的名单呢?你确定你确实需要吗?


void *元素数组支持的想法是因为列表上的几个操作可以移动到非模板化代码,因此减少了生成代码的数量。

如果类型足够小(即void *),QList将项目直接存储在sizeof(T) <= sizeof(void*)数组中,并且如果类型可以通过memmove在内存中移动。否则,每个项目将通过new在堆上分配,并且数组将存储指向这些项目的指针。一组类型特征用于确定如何处理每种类型,请参阅Q_DECLARE_TYPEINFO

虽然理论上这种方法在实践中听起来很有吸引力:

  • 对于小于void *(char; int和64位浮点数等)的所有原始类型,您将浪费数组中已分配空间的50%到75%
  • 对于所有大于void *的可移动类型(32位,QVariant上的双倍,......),您需要为列表中的每个项目支付堆分配(加上数组本身)
  • QList代码通常不如QVector one
  • 优化
  • 这些天的编译器在合并模板实例化方面做得非常好,因此这种设计的最初原因会丢失。

Today it's a much better idea to stick with QVector。不幸的是,Qt API在任何地方公开QList并且无法改变它们(我们需要C ++ 11来定义QList作为QVector的模板别名......)

答案 3 :(得分:0)

我使用qt4.8.6在Ubuntu 32bit中使用4GB RAM进行测试。我的最大尺寸是268,435,450

我使用qt4.8.4在Windows7 32bit和4GB RAM中进行测试。我的最大尺寸是134,217,722

发生此错误:&#39; std :: bad_alloc&#39;

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QList<bool> li;
    for(int i=0; ;i++)
    {
        li.append(true);
        if(i>268435449)
            qDebug()<<i;
    }
    return a.exec();
}

输出是:

  

268435450

     

在抛出&#39; std :: bad_alloc&#39;
的实例后终止调用   what():std :: bad_alloc