【问题标题】:Traversing a vector in reverse direction with size_t values使用 size_t 值反向遍历向量
【发布时间】:2015-02-08 17:16:57
【问题描述】:

我想以相反的方向遍历向量的值。如您所知,向量的大小为 size_t。当我使用以下代码时:

for(size_t r=m.size()-1; r >= 0; r--)
{
    x[r] = f[r];
    for(size_t c = r+1; c < m.size(); c++)
    {
        x[r] -= m[r][c] * x[c];
    }
}

我将超出向量的范围,因为 r 在递减 r = 0 后将变为 4294967295。

我没有更改 r 的类型,因为在我的项目中,我将警告视为错误,所以它应该是 size_t 或者我应该强制转换它,这并不有趣。

【问题讨论】:

  • r &gt;= 0 &amp;&amp; r &lt; m.size()
  • 使用反向迭代器怎么样?
  • 我同意猫,看起来你可以使用 rbegin()/rend()。
  • @ShmilTheCat 除了他正在索引到xrm
  • 是的!反向迭代器很有趣,但在我的整个代码中,我使用的是这种类型的迭代器,在这里只使用一次并不有趣。

标签: c++ vector


【解决方案1】:

如果您确实想使用size_t 进行索引,则可以将循环表述如下。

for(size_t r = m.size(); r > 0; r--)
{
    x[r-1] = f[r-1];
    for(size_t c = r; c < m.size(); c++)
    {
        x[r-1] -= m[r-1][c] * x[c];
    }
}

基本上你会从m.size() 迭代到1 并通过在循环内移动来补偿;但这个解决方案可能有点难以理解。在this question 中,建议的解决方案是使用reverse_iterator,可以将其视为对索引的适当抽象。 this question 更深入地介绍了整个主题。

【讨论】:

  • DRY: auto r1 = r - 1; 并在循环中使用 r1(或切换名称 rr1 以使循环体更具可读性)。
  • @JamesKanze 有趣;它让你感到困惑,它向我表达了意图。但我相信我们已经讨论过了。
  • 我坚信“正确”的方法是重新设计实现,使索引计算一开始就没有必要。
  • @Griwes 对读者隐藏类型,尤其是当它产生如此大的差异时,是一种混淆。它也非常脆弱,因为代码中其他地方的更改可能会导致此处的语义发生重大变化。将auto 用于整数类型总是是个问题,因为知道类型是有符号还是无符号至关重要;语义发生了根本性的变化。
  • James 没有指出不知道整数提升规则是个问题。他指出,在其他地方改变事物会在语义上发生重大变化。
【解决方案2】:

这是我最喜欢的方式:

std::size_t r = m.size();
while (r --> 0)
{
    // access m[r]
}

【讨论】:

  • 我意识到这很好很漂亮,但我强烈建议不要使用 --&gt; 后减量,然后在同一个表达式中比较会混淆这里发生的事情
  • @Mgetz 一旦了解了后递减的工作原理,这里发生的事情就应该很明显了。我希望认为不理解这种情况只是缺乏语言知识。
  • @lisyarus 朴英裴所链接的问题完全存在的事实应该证明否则。
  • 在同一个语句中进行后递减和比较并不是那么有罪,但是将其分解为 --&gt; 会使没有经验的读者感到困惑。
  • 通常应避免在条件中修改状态,因为它会导致读者意想不到的副作用。将-- 放在循环顶部的单独语句中有什么问题,不能忽略它。
【解决方案3】:

好吧,你应该尽可能避免size_t,因为它是 无符号类型,并且无符号类型在 C++ 中表现不佳,至少 说到算术。但无论类型如何,通常 我将用于反向迭代的成语(假设由于某种原因我不能 只需使用反向迭代器,这将是自然的解决方案) 是这样的:

int r = m.size();     //  but size_t r would work here too.
while ( r > 0 ) {
    -- r;
    //  ...
}

将递减移动到循环的顶部可以解决大部分问题 问题,而且恕我直言更清楚。

【讨论】:

  • 问题是 m.size() 是 size_t 并且会发出警告。
  • 所以投吧。这就是我要做的。这是最清楚的方法。只要您的向量不是非常庞大,那就是 ;p
  • @mmostajab 我知道。这是标准中的设计缺陷(由于在设计库时对某些硬件的限制)。如果您确定 m 永远不会大于 INT_MAX (并且有很多可以保证这一点的上下文),那么只需转换即可。否则,请使用更大的有符号整数类型。 (在我提供的代码中,size_t 确实可以工作。但它可能会在以后导致问题。)
  • @Griwes 定义做错事的事情比未定义的行为更糟​​糕。无论哪种情况,您都不能指望行为是您想要的。由于几个原因,C++ 中的无符号类型被破坏为算术类型。根据上下文,您可能想使用std::ptrdiff_t,但在很多情况下,您可以知道int 不会溢出,并安全地使用它。
  • @Griwes 您可以推断在溢出的情况下两者都不会做您想做的事情。这就是全部。通常,C++ 中无符号整数类型的语义不适用于算术值。他们不工作;尝试将它们用于算术值是一种反模式,应该避免。
【解决方案4】:

无符号算术在 C++ 中定义良好,所以我将与“溢出”进行比较:

for (size_t r = m.size() - 1; r != -1; r--)

在循环条件下,-1 会自动转换为具有正确值的无符号数。

【讨论】:

  • 依赖溢出非常令人困惑。
  • @LightnessRacesinOrbit:由于无符号整数非常棒,代码定义明确。
【解决方案5】:

使用 Boost.Range:

for (auto r : boost::irange(std::size_t(0), m.size()) | boost::adaptors::reversed) {
    x[r] = f[r];
    for (auto c : boost::irange(r + 1, m.size())) {
        x[r] -= m[r][c] * x[c];
    }
}

【讨论】:

    【解决方案6】:

    对于仍在寻找方法的任何人,请使用容器中的difference type,只需对代码稍作修改,而不是使用size_t r = m.size()-1,请使用以下代码

    std::vector&lt;T&gt;::difference_type r = m.end()-m.begin()

    或者你可以使用

    std::ptrdiff_t r = m.end()-m.begin() 并且循环将起作用 ptrdiff_t 只是标记两个迭代器之间距离的别名。

    【讨论】:

      猜你喜欢
      • 2012-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多