为什么QVector::size返回int ?< / h1 >

Why QVector::size returns int?

本文关键字:lt h1 gt QVector size 返回 int 为什么      更新时间:2023-10-16

std::vector::size()返回一个无符号的size_type,通常与size_t相同,例如在64位平台上它是8字节。

相比之下,QVector::size()返回int,即使在64位平台上通常也是4字节,并且它是有符号的,这意味着它只能走到2^32的一半。

为什么?这似乎非常不合逻辑,而且在技术上也有限制,虽然您不太可能需要超过2^32个元素数量,但使用signed int将这个范围减少了一半,没有明显的好理由。也许是为了避免编译器警告那些懒得将i声明为uint而不是int的人,他们决定让所有容器返回一个没有意义的大小类型是一个更好的解决方案?原因不可能那么愚蠢吧?

这个问题至少从Qt 3开始就被讨论了好几次,QtCore的维护者在一段时间前表示,如果Qt 7有变化的话,那么在此之前不会发生任何变化。

当讨论还在进行的时候,我想有人迟早会在Stack Overflow上提起它…可能在其他论坛和Q/A中也有。让我们试着揭开这个情况的神秘面纱。

一般来说,您需要理解这里没有更好或更差的地方,因为QVector而不是std::vector的替代品。后者不做任何写时复制(COW),这是有代价的。基本上,它意味着一个不同的用例。它主要用于Qt应用程序和框架本身,最初用于早期的QWidgets。

size_t也有自己的问题,毕竟我将在下面指出。

不用我向你解释维护者的话,我直接引用Thiago的话来传达官方立场的信息:

有两个原因:

1)它是有符号的,因为我们在API的几个地方需要负值:indexOf()返回-1表示未找到值;许多"来自"参数可以取负值以表示从末尾开始计数。所以即使如果我们使用64位整数,我们需要它的带符号版本。这是POSIX ssize_t或Qt qintptr.

当您隐式地将无符号转换为时,这也避免了符号更改警告签名:

-1 + size_t_variable        => warning
size_t_variable - 1     => no warning

2)它只是"int",以避免转换警告或与使用大于int.

的整数

io/qfilesystemiterator_unix.cpp

size_t maxPathName = ::pathconf(nativePath.constData(), _PC_NAME_MAX);
if (maxPathName == size_t(-1))

io/qfsfileengine.cpp

if (len < 0 || len != qint64(size_t(len))) {

io/qiodevice.cpp

qint64 QIODevice::bytesToWrite() const
{
return qint64(0);
}
return readSoFar ? readSoFar : qint64(-1);

这是一封来自Thiago的邮件,然后还有另一封邮件,你可以找到一些详细的答案:

即使在今天,核心内存超过4gb(甚至2gb)的软件是一个例外,而不是规则。看的时候请小心某些进程工具的内存大小,因为它们不表示实际内存使用。

在任何情况下,我们在这里谈论的是一个单一的容器寻址大于2gb的内存。因为隐式共享&即写即拷Qt容器的本质,这可能是非常低效的。你需要在编写此类代码时要非常小心,以避免触发COW等内存使用翻倍甚至更糟。此外,Qt容器不处理OOM情况下,所以如果你接近你的内存限制,Qt容器都是错误的工具。

我的系统中最大的进程是qtcreator,它也是唯一的在VSZ中超过4gb标记(4791 MB)。你可以说它是指示需要64位容器,但您错了:

  • Qt Creator没有任何需要64位大小的容器,它简单地需要64位指针

  • 没有使用4gb内存。这只是VSZ(映射内存)。总目前Creator可访问的内存只有348.7 MB。

  • 因为是64位的,所以占用了超过4gb的虚拟空间应用程序。因果关系和你想的正好相反期望。为了证明这一点,我检查了有多少虚拟空间被消耗填充:800 MB。32位应用程序永远不会这样做,这是19.5%的内存

(填充是分配的虚拟空间,但不支持任何东西;这只是这样别的东西就不会被映射到这些页面)

进一步了解Thiago的回答,请参阅:

就我个人而言,我非常高兴Qt集合大小被签名。似乎让我感到奇怪的是,一个整数值可能会在表达式中使用减法是无符号的(例如size_t)。

无符号整数不能保证包含

的表达式这个整数永远不会是负数。它只保证了结果这绝对是一场灾难。

另一方面,C和c++标准定义了unsigned的行为溢出和下溢

有符号整数不会溢出或下溢。我是说,他们会的,因为这些类型和CPU寄存器的比特数是有限的,但是标准说它们不喜欢。这意味着编译器将始终优化假设你没有过度

的例子:

for (int i = 1; i >= 1; ++i)

这被优化为无限循环,因为有符号整数不会溢出。如果将其更改为unsigned,则编译器知道它可能溢出然后回到原点。

有些人不喜欢:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30475

unsigned的数字是一些n的mod2^n的值。

有符号数是有界整数。

使用无符号值作为"正整数"的近似值会遇到这样的问题:普通值靠近域的边缘,在那里无符号值的行为与普通整数不同。

优点是无符号近似达到更高的正整数,并且在/overflow下定义良好(如果作为Z的模型来看是随机的)。

但说真的,ptrdiff_t会比int好。