【问题标题】:Can this C++ method be simplified?这个 C++ 方法可以简化吗?
【发布时间】:2018-04-18 05:06:45
【问题描述】:

背景:

我一直在将gap buffer 算法实现为具有匹配自定义迭代器的 STL 容器。除了其他成员之外,Buffer 类还有两个内部指针_gapStart_gapEnd,它们分别代表间隙的开始和结束。

BufferIterator 有两个成员 _buffer 是对其迭代的 Buffer 类的引用,_pos 是 Buffer 中的当前位置。它与普通迭代器的不同之处在于,当它在缓冲区中前后移动时,它应该“跳过”间隙。

为此,我有下面的代码,它实现了operator+=(所有其他迭代器算术运算符都是根据它定义的)。这段代码有效,但我有一种唠叨的感觉,它可以变得更简单。

BufferIterator& operator+=(const difference_type& n) {
   auto count = n;

   if (count >= 0) {
        while (count--) {
            ++_pos;
            if (_pos == _buffer._gapStart) {
                _pos += (_buffer._gapEnd - _buffer._gapStart);
            }
        }
    } else {
        while (count++) {
            --_pos;
            if (_pos == _buffer._gapEnd) {
                _pos -= (_buffer._gapEnd - _buffer._gapStart);
            }
        }
    }

    return *this;
}

所以我想用下面的版本替换它。但是它不起作用;它会导致段错误。为什么?在我看来,它应该是完全等价的,但我不知道为什么不是。

BufferIterator& operator+=(const difference_type& n) {

    if (n >= 0) {
        _pos += n;
        if (_pos >= b._gapStart) {
            _pos += (b._gapEnd - b._gapStart);
        }
    } else {
        _pos -= n;
        if (_pos <= b._gapEnd) {
            _pos -= (b._gapEnd - b._gapStart);
        }
    }

    return *this;
}

谁能帮我理解这个?有没有更简单的方法来实现第 1 版,或者它真的是最好的实现方法?

顺便说一句,如果有助于在上下文中查看代码,我的简单编辑器可以在 on Github 找到。

【问题讨论】:

  • @PaulRooney 整个课程的代码已发布在 codereview 上,我得到了宝贵的反馈,但不是针对这一点。我在这里而不是那里问,部分原因是我想了解为什么这两个版本不相等,而且我认为这种问题更多的是在 SOs bailiwick。
  • 您的第二个版本中有一个错误。想想_gapStart = 2; _gapEnd = 4; pos = 10;n= 10; 新的 pos 现在应该是什么? PS 这是单元测试应该捕捉到的东西。
  • 在第一个例子中,_pos += (_buffer._gapEnd - _buffer._gapStart);之后不应该有一个break语句吗?除非您要遍历多个缓冲区?您当前的代码并不明显
  • @smac89 有一个缺失的 ) 我已修复,这可能会让您认为,但不,不需要休息。
  • @LokiAstari 感谢 Jarod42,我明白了问题所在。关于单元测试的要点。我是一名专业开发人员,但只是 C++ 的爱好者。我做这样的小项目来保持我的技能,但我还不知道所有的专业工具。有机会我会研究单元测试框架。

标签: c++ algorithm debugging c++14


【解决方案1】:

第一个版本可以这样简化:

BufferIterator& operator+=(const difference_type& n) {
   auto count = n;

   if (count >= 0) {
        while (count--) {
            ++_pos;
            if (_pos == _buffer._gapStart) {
                _pos = _buffer._gapEnd;
            }
        }
    } else {
        while (count++) {
            --_pos;
            if (_pos == _buffer._gapEnd) {
                _pos = _buffer._gapStart;
            }
        }
    }
    return *this;
}

要删除循环,您的代码可能如下所示:

BufferIterator& operator+=(const difference_type& n) {
    if (n >= 0) {
        if (_pos < b._gapStart && b._gapStart <= _pos + n) {
            _pos += b._gapEnd - b._gapStart;
        }
    } else {
        if (_pos + n <= b._gapEnd && b._gapEnd < _pos) {
            _pos -= (b._gapEnd - b._gapStart);
        }
    }
    _pos += n;
    return *this;
}

【讨论】:

  • 谢谢。我用了你的第二个版本。我做了一个小的优化,我删除了每个 if/else 块的最后一行,并在返回之前将其替换为 _pos += n;
  • @Jaldhar,只是为了确保:_pos += n 在返回之前不等于您最初在问题中的内容。无论n 的符号如何,您的原始代码(以及因此,Jarod42 的代码)导致_pos 增加,因为如果n &gt;= 0,您添加n,否则您减去n,但n 是一个负数,所以你添加了abs(n)。通过您所做的优化,您在第二种情况下减少了pos。如果这是您所期望的,那很好,但只是想引起您对这个细节的注意。
  • @FreeNickname 是的,这是预期的行为。看来我最初编写该代码时确实没有正确思考!
  • @Jaldhar 它发生了 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-04
  • 2021-06-23
  • 2020-11-21
  • 2017-07-01
  • 1970-01-01
相关资源
最近更新 更多