【问题标题】:Why QVector::size returns int?为什么 QVector::size 返回 int?
【发布时间】:2014-12-24 12:55:09
【问题描述】:

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

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

这是为什么呢?这似乎很不合逻辑,并且在技术上也有限制,虽然您可能需要超过 2^32 个元素的可能性也不大,但使用有符号的 int 会毫无理由地将该范围缩小一半。也许是为了避免对那些懒得将i 声明为uint 而不是int 的人发出编译器警告,后者决定让所有容器返回一个没有意义的大小类型是更好的解决方案?原因不可能那么傻吧?

【问题讨论】:

  • 它实际上可能是那么愚蠢。许多(广泛使用和尊重的)库代码都包含像这样的脑死文体错误。你会惊讶于有多少其他有才华的程序员甚至不知道size_t这样的东西的存在...
  • 使用大于 2GB 的 QByteArray 会很有趣,这在我的领域中实际上是完全可以实现的......
  • @userXXX 完全同意。现在,搜索几个“便携式”开源库/应用程序并阅读其源代码。当您发现它们充满了一堆未定义的行为、不可移植的结构、易于破坏的假设等时,会感到震惊。那是因为,根据我的经验,大多数程序员都是实用主义者(“懒惰”的委婉说法)并且不要按照语言标准编程,而是按照他们中间不称职的老师(!)和/或同事建议他们做的任何事情。这很可悲。非常非常伤心。
  • 太糟糕了,也很讽刺,我一直在努力开发使用无符号整数迭代容器的良好做法,现在我收到编译器警告作为对它的惩罚。
  • 也许不是这个原因,但还是哈哈:qt-project.org/doc/qt-5/qvector.html#fill

标签: c++ qt size qtcore qvector


【解决方案1】:

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

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

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

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

不用我给你解释maintainer,我直接引用Thiago来携带official stance的消息:

有两个原因:

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);

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

即使在今天,核心内存超过 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。

  • 而且它使用了超过 4 GB 的虚拟空间因为它是 64 位的 应用。因果关系与你想的相反 预计。作为证明,我检查了 填充:800 MB。 32 位应用程序永远不会这样做,这是 19.5% 4 GB 上的可寻址空间。

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

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

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

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

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

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

例子:

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

这是针对无限循环优化的,因为有符号整数不会溢出。 如果将其更改为无符号,则编译器知道它可能会溢出 然后归零。

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

【讨论】:

【解决方案2】:

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

有符号数是有界整数。

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

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

但实际上,ptrdiff_t 会比 int 更好。

【讨论】:

  • 我想到的另一个原因:如果添加一个带符号类型的无符号,则生成的类型是无符号的。这可能会导致意外且难以追踪的行为。如果您将 size() 添加到某个其他值,结果是否定的怎么办?除非以某种方式将其转换回有符号整数,否则您可能会遇到麻烦。
  • @TaylorBrandstetter 是的,这是可能的;通常,使用有符号值更方便(轻率地......)。但正如这个答案中很好指出的那样,仍然会有ptrdiff_t...
  • @Taylor 你得到一个很大的正数。这不是“实整数”行为的一个很好的近似,但却是一种常见的情况。根据我的经验,最常见的有符号整数溢出源实际上是无符号到有符号的转换。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-22
  • 1970-01-01
  • 1970-01-01
  • 2013-07-30
  • 1970-01-01
  • 1970-01-01
  • 2019-10-12
相关资源
最近更新 更多