为什么QVector :: size返回int? [英] Why QVector::size returns int?

查看:459
本文介绍了为什么QVector :: size返回int?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

std :: vector :: size()返回一个 size_type ,它是无符号的, code> size_t ,例如



在对比中, QVector :: size()返回一个 int 这通常是4个字节,即使在64位平台上,并且它是签名的,这意味着它只能到一半到2 ^ 32。



为什么?这似乎是不合逻辑的,也是技术上的限制,虽然你也许不需要超过2 ^ 32的数量的元素,使用signed int剪切的范围在一半,没有明显的好理由。也许避免编译器警告为人太懒地声明 i 作为 uint 而不是 int 谁决定让所有容器返回一个没有意义的大小类型是更好的解决方案?

解决方案

自Qt 3起至少已讨论过多次,而QtCore维护者表示那么以前没有任何改变会发生,直到Qt 7,如果它曾经做过。



当讨论发生时,我认为有人会把它放在堆栈溢出早晚或许更多的其他论坛和Q / A。让我们尝试去解释这种情况。



一般来说,你需要明白这里没有更好或更坏的情况,因为 QVector 替换 std :: vector 。后者不做任何写时复制(COW),并且带有价格。它基本上是为不同的用例。它主要用于Qt应用程序和框架本身,最初是为早期的QWidgets。



size_t



如果没有我向你解释维护者,我将直接引用Thiago来传达< a href =http://lists.qt-project.org/pipermail/interest/2013-September/008592.html>正式立场:



< blockquote>

有两个原因:



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



当你隐式转换unsigneds为
signed时,这也避免了符号更改警告:




  -1 + size_t_variable => warning 
size_t_variable - 1 =>没有警告




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的一封电子邮件,然后这里有另一个,您可以在其中找到一些详细的答案:


即使今天,具有超过4 GB(甚至2 GB)
的核心内存的软件也是例外,而不是规则。请注意一些过程工具的
内存大小,因为它们不代表实际内存
的用法。



无论如何,我们在这里谈论有一个容器寻址
超过2 GB的内存。由于隐式共享& copy-on-write
Qt容器的性质,这可能是非常低效的。你需要
在写这样的代码时要非常小心,以避免触发COW,因此
加倍或更糟的内存使用。此外,Qt容器不处理OOM
的情况,所以如果你在任何接近你的内存限制,Qt容器
是错误的工具使用。



我在我的系统上最大的进程是qtcreator,它也是唯一的
跨越VSZ(4791 MB)的4 GB标记。你可以认为它是一个
表示需要64位容器,但是你错了:




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


  • 的内存。这只是VSZ(映射内存)。创建者当前可访问的总共
    RAM仅为348.7 MB。


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




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


进一步讨论Thiago的回应,请参阅:




我个人很高兴Qt集合大小签名。看起来
向我表示,使用
减法可能在表达式中使用的整数值是无符号的(例如size_t)。



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



C和C ++标准定义了无符号
溢出和下溢的行为。



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



示例:




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


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



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



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?

解决方案

This has been discussed several times since Qt 3 at least and the QtCore maintainer expressed that a while ago no change would happen until Qt 7 if it ever does.

When the discussion was going on back then, I thought that someone would bring it up on Stack Overflow sooner or later... and probably on several other forums and Q/A, too. Let us try to demystify the situation.

In general you need to understand that there is no better or worse here as QVector is not a replacement for std::vector. The latter does not do any Copy-On-Write (COW) and that comes with a price. It is meant for a different use case, basically. It is mostly used inside Qt applications and the framework itself, initially for QWidgets in the early times.

size_t has its own issue, too, after all that I will indicate below.

Without me interpreting the maintainer to you, I will just quote Thiago directly to carry the message of the offical stance on:

For two reasons:

1) it's signed because we need negative values in several places in the API: indexOf() returns -1 to indicate a value not found; many of the "from" parameters can take negative values to indicate counting from the end. So even if we used 64-bit integers, we'd need the signed version of it. That's the POSIX ssize_t or the Qt qintptr.

This also avoids sign-change warnings when you implicitly convert unsigneds to signed:

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

2) it's simply "int" to avoid conversion warnings or ugly code related to the use of integers larger than 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);

That was one email from Thiago and then there is another where you can find some detailed answer:

Even today, software that has a core memory of more than 4 GB (or even 2 GB) is an exception, rather than the rule. Please be careful when looking at the memory sizes of some process tools, since they do not represent actual memory usage.

In any case, we're talking here about having one single container addressing more than 2 GB of memory. Because of the implicitly shared & copy-on-write nature of the Qt containers, that will probably be highly inefficient. You need to be very careful when writing such code to avoid triggering COW and thus doubling or worse your memory usage. Also, the Qt containers do not handle OOM situations, so if you're anywhere close to your memory limit, Qt containers are the wrong tool to use.

The largest process I have on my system is qtcreator and it's also the only one that crosses the 4 GB mark in VSZ (4791 MB). You could argue that it is an indication that 64-bit containers are required, but you'd be wrong:

  • Qt Creator does not have any container requiring 64-bit sizes, it simply needs 64-bit pointers

  • It is not using 4 GB of memory. That's just VSZ (mapped memory). The total RAM currently accessible to Creator is merely 348.7 MB.

  • And it is using more than 4 GB of virtual space because it is a 64-bit application. The cause-and-effect relationship is the opposite of what you'd expect. As a proof of this, I checked how much virtual space is consumed by padding: 800 MB. A 32-bit application would never do that, that's 19.5% of the addressable space on 4 GB.

(padding is virtual space allocated but not backed by anything; it's only there so that something else doesn't get mapped to those pages)

Going into this topic even further with Thiago's responses, see this:

Personally, I'm VERY happy that Qt collection sizes are signed. It seems nuts to me that an integer value potentially used in an expression using subtraction be unsigned (e.g. size_t).

An integer being unsigned doesn't guarantee that an expression involving that integer will never be negative. It only guarantees that the result will be an absolute disaster.

On the other hand, the C and C++ standards define the behaviour of unsigned overflows and underflows.

Signed integers do not overflow or underflow. I mean, they do because the types and CPU registers have a limited number of bits, but the standards say they don't. That means the compiler will always optimise assuming you don't over- or underflow them.

Example:

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

This is optimised to an infinite loop because signed integers do not overflow. If you change it to unsigned, then the compiler knows that it might overflow and come back to zero.

Some people didn't like that: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30475

这篇关于为什么QVector :: size返回int?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆