22

std::vector::size() returns a size_type which is unsigned and usually the same as size_t, e.g. it is 8 bytes on 64bit platforms.

In constrast, QVector::size() returns an int which is usually 4 bytes even on 64bit platforms, and at that it is signed, which means it can only go half way to 2^32.

Why is that? This seems quite illogical and also technically limiting, and while it is nor very likely that you may ever need more than 2^32 number of elements, the usage of signed int cuts that range in half for no apparent good reason. Perhaps to avoid compiler warnings for people too lazy to declare i as a uint rather than an int who decided that making all containers return a size type that makes no sense is a better solution? The reason could not possibly be that dumb?

4

2 回答 2

18

至少从 Qt 3 开始,这个问题已经讨论过好几次了,QtCore 维护者表示不久前不会发生任何变化,直到 Qt 7 才会发生。

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

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

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

无需我向您解释维护者,我将直接引用蒂亚戈来传达官方立场的信息:

有两个原因:

1) 它是有符号的,因为我们在 API 中的几个地方需要负值: indexOf() 返回 -1 表示未找到值;许多“from”参数可以采用负值表示从末尾开始计数。所以即使我们使用 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);

那是来自蒂亚戈的一封电子邮件,然后您可以在另一封电子邮件中找到一些详细的答案:

即使在今天,核心内存超过 4 GB(甚至 2 GB)的软件也是一个例外,而不是规则。在查看某些处理工具的内存大小时请小心,因为它们并不代表实际的内存使用情况。

无论如何,我们在这里谈论的是让一个容器寻址超过 2 GB 的内存。由于 Qt 容器的隐式共享和写入时复制的性质,这可能会非常低效。编写此类代码时需要非常小心,以避免触发 COW,从而使内存使用量增加一倍或更差。此外,Qt 容器不处理 OOM 情况,因此如果您的内存限制接近,Qt 容器是错误的工具。

我系统上最大的进程是 qtcreator,它也是唯一一个在 VSZ (4791 MB) 中超过 4 GB 标记的进程。您可能会争辩说这表明需要 64 位容器,但您错了:

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

  • 它没有使用 4 GB 的内存。那只是VSZ(映射内存)。Creator 当前可访问的总 RAM 仅为 348.7 MB。

  • 因为它是一个 64 位应用程序,所以它使用了超过 4 GB 的虚拟空间。因果关系与您所期望的相反。作为证明,我检查了填充消耗了多少虚拟空间:800 MB。32 位应用程序永远不会这样做,这是 4 GB 上可寻址空间的 19.5%。

(填充是分配的虚拟空间,但没有任何支持;它只是在那里,以便其他东西不会映射到这些页面)

通过蒂亚戈的回应进一步探讨这个话题,请参阅:

就个人而言,我很高兴签署了 Qt 集合大小。对我来说,可能在使用 减法的表达式中使用的整数值是无符号的(例如 size_t),这似乎很疯狂。

无符号整数不能保证涉及该整数的表达式永远不会是负数。它只保证结果将是一场绝对的灾难。

另一方面,C 和 C++ 标准定义了无符号上溢和下溢的行为。

有符号整数不会上溢或下溢。我的意思是,他们这样做是因为类型和 CPU 寄存器的位数有限,但标准说他们没有。这意味着编译器将始终优化假设您没有溢出或下溢。

例子:

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

这已针对无限循环进行了优化,因为有符号整数不会溢出。如果将其更改为无符号,则编译器知道它可能会溢出并返回零。

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

于 2014-10-29T01:50:58.743 回答
2

unsigned数字是2^n一些的值 mod n

有符号数是有界整数。

使用无符号值作为“正整数”的近似值会遇到一个问题,即公共值靠近域的边缘,其中无符号值的行为与普通整数不同。

优点是无符号近似可以达到更高的正整数,并且下溢/上溢定义明确(如果作为 Z 的模型是随机的)。

但真的,ptrdiff_t会比int

于 2014-10-28T22:57:58.610 回答