无符号整数相减的有符号结果是什么?

3

我正在尝试创建一个类,类似于vector<string>,以及另一个类,类似于它的迭代器(纯粹是从C++ Primer(对于那些感兴趣的人来说,这是练习14.28)中的练习)。 迭代器类通过具有一个vector<string>::size_type成员(称为curr)来表示向量的索引。 当尝试为迭代器定义自己的减法运算符时,我遇到了一些困惑。 最终,它应该像减去两个迭代器一样工作,并在必要时产生负值。 我定义的函数如下:

??? operator-(const iterator& lhs, const iterator& rhs){
    return (lhs.curr - rhs.curr);
}

另一种我困惑的版本:

#include <vector>
#include <string>
#include <iostream>

using namespace std;

int main(){

    vector<string>::size_type x = 5, y = 3;

    ??? z = (y-x); //what should ??? be if I want -2?

    cout << z;

}

(y-x)的值为-2,但由于它是一个32位无符号表达式,在存储到z之前会回绕到4294967294。我无法确定如何定义返回类型,以便在rhs(y)比lhs(x)更靠后时,返回正确的负值(存储在z中)。

我认为vector<string>::difference_type可能会起到这个作用,但我发现size_type表示32位无符号整数,而difference_type表示32位有符号整数,因此使用有符号整数会产生未定义的行为-尽管在我的计算机上它产生了正确的结果。我可以将所有内容强制转换为long long int并返回long long int,但我觉得这样有点过于粗暴。


我应该使用什么类型的迭代器差异来消除“可能丢失数据”的警告? - phuclv
你尝试过使用“auto”吗?或者你不想使用它? - RaGa__M
@RichardGeorge auto 只会将 z 设置为无符号类型,这并不是我们想要的。 - AntiElephant
为了处理所有可能的结果范围(从[-INT_MAX; INT_MAX]),您不能使用(有符号/无符号)int - Jarod42
1个回答

8
正确的类型确实是vector<string>::difference_type。你可以像这样轻松地实现迭代器减法:
difference_type operator- (const iterator &lhs, const iterator &rhs)
{
  if (rhs.curr >= lhs.curr) return static_cast<difference_type>(rhs - lhs);
  else return - static_cast<difference_type>(lhs - rhs);
}

实际的标准库实现可能不需要这样做,因为它们通常针对特定编译器并可以使用内部知识来处理实现定义的行为,例如将无符号值转换为有符号类型时超出有符号范围的结果。


@simplicisveritatis 不完全是这样。无符号数相减的结果也是无符号的,abs() 无法解决这个问题。 - Angew is no longer proud of SO
谢谢回复。但是如果rhs(或y)是4000000000,而lhs(或x)是3,那么我在我的机器上得到的答案是294967299,因为有符号整数溢出,但我想要的答案是3999999997。 - AntiElephant
嗯,实际上现在我想了一下。difference_type 可能被_保证_保存两个迭代器之间的差异(虽然我找不到引用),这意味着尽管 size_type 足够大以容纳 2^32,但向量大小不能超过 2^31。因此,我永远不必担心或期望担心 curr 大于 2^31 的情况。所以谢谢。 - AntiElephant
这里没有涉及未定义的行为。无符号类型的两个值之间的差异也是无符号的,那么就需要进行强制转换。在减法步骤中可能会有模数减法,但这是完全定义明确的。在强制转换过程中不会出现“溢出”--如果该值在目标类型中不可表示,则结果是实现定义的。这可能还不够好,但它并不是未定义的行为。 - Ben Voigt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接