【问题标题】:Condensed for loop.. (C++) [duplicate]压缩for循环..(C++)[重复]
【发布时间】:2018-04-11 21:49:56
【问题描述】:

我偶然发现了这段代码并试图理解它,某些部分很清楚但不是 for 循环:

forward_list<Class> obj;
auto b_end = obj.before_begin();

for (auto& _ : obj)
    ++b_end ;

obj.insert_after(b_end, Class newObj);

不完全确定 for 循环在做什么。有人可以打破 for 循环并帮助我理解它吗?

编辑: 这个问题被标记为重复,但其他线程没有提供足够的信息和/或太旧。

【问题讨论】:

  • 我将无法发布完整的代码,但据我所知,代码的目标是将 newObj 始终插入列表的末尾(技术上不是在末尾,而是一个在结束之前,因为它可能指向 nullptr??)
  • @Jin:minimal reproducible example 不是完整代码。它是关于创建一个玩具示例并重现您看到的行为。一个非常有用的调试和理解练习。
  • 我认为auto b_end = obj.before_begin() + std::distance(std::begin(obj), std::end(obj)); 会起作用并消除手动循环。我说的对吗?
  • @FredLarson 是的,这可行,但您需要遍历列表两次,以便将迭代器移至最后一个元素。

标签: c++ insert iterator singly-linked-list


【解决方案1】:

std::forward_list 是一个带有 forward_iterators 的顺序容器。它是一个单向单链表。要将值插入列表,您只能使用方法 insert_after 指定范围内的迭代器 [begin(), end()) 或方法 before_begin() 返回的迭代器。

来自 C++ 标准

5 要求:位置是 before_begin() 或者是可取消引用的 [begin(), end()) 范围内的迭代器。

因此,如果要将新值附加到列表的末尾,则必须将迭代器移动到与列表中最后一个元素对应的位置。

所以这个循环命名为基于范围的for循环

for (auto& _ : obj)
    ++b_end ;

将迭代器b_end逐步移动到列表中最后一个元素所占据的位置。所以现在使用迭代器,您可以使用 insert_after 方法将新值附加到列表中。

考虑一个简单的演示程序。

#include <iostream>
#include <forward_list>

int main()
{
    std::forward_list<int> lst = { 1, 2 };

    auto b_end = lst.before_begin();

    for (const auto &_ : lst)
    {
        ++b_end;
        std::cout << *b_end << '\n';
    }
    std::cout << std::endl;

    lst.insert_after(b_end, 3);

    for (const auto &_ : lst) std::cout << _ << ' ';
    std::cout << std::endl;

    return 0;
}

程序输出是

1
2

1 2 3

首先迭代器b_end指向列表中第一个元素之前。

    auto b_end = lst.before_begin();
                     ^^^^^^^^^^^^^^

之后,由于列表仅包含两个元素,因此在将进行两次迭代的循环中,迭代器首先将移动到对应于第一个元素的位置,然后移动到对应于第二个元素的位置。

现在使用获得的迭代器,我们可以在值 2 之后添加值 3。

【讨论】:

    【解决方案2】:

    这个:

    forward_list<Class> obj;
    

    声明std::forward_listClass-es 名为obj。由于在代码中某处使用了using namespace std;,因此省略了std:: 部分。 这个:

    auto b_end = obj.before_begin();
    

    定义一个迭代器,指向您的obj 列表中的std::forward_list::before_begin 位置。 这个:

    for (auto& _ : obj)
        ++b_end;
    

    是一个 range based for loop,它使用一个通过引用传递的奇怪命名的 _ 变量。在这个循环中,b_end 在每次迭代中都会递增。 最后:

    obj.insert_after(b_end, Class newObj);
    

    尝试在b_end 位置之后插入Class 类型的新newObj,但编译失败,因为它可能应该是:

    Class newObj;
    obj.insert_after(b_end, newObj);
    

    话虽如此,_ 只是一个变量名。它是一个(有点不寻常)有效的变量标识符。在这里,_ 变量本身没有在 for 循环中以任何方式使用,所以整个事情可以重写为:

    for (auto el : obj){
        ++b_end;
    }
    

    auto 关键字代表auto specifier

    【讨论】:

      猜你喜欢
      • 2021-07-31
      • 1970-01-01
      • 2020-11-22
      • 2019-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多