c – std :: list和std :: for_each:我的结局在哪里?

请考虑以下最小示例:
#include <functional>
#include <algorithm>
#include <list>

int main() {
    std::list<std::function<void()>> list;
    list.push_back([&list](){ list.push_back([](){ throw; }); });
    std::for_each(list.cbegin(),list.cend(),[](auto &&f) { f(); });
}

它在运行时编译并抛出异常.
我的猜测是只有第一个lambda由std :: for_each执行,但显然我错了:如果我在列表的末尾附加另一个lambda,迭代也会到达lambda.

让我们恢复示例(push_front而不是push_back和crbegin / crend而不是cbegin / cend):

#include <functional>
#include <algorithm>
#include <list>

int main() {
    std::list<std::function<void()>> list;
    list.push_front([&list](){ list.push_front([](){ throw; }); });
    std::for_each(list.crbegin(),list.crend(),[](auto &&f) { f(); });
}

由于前面的例子,我预计这也会编译和崩溃.
相反,它编译并且不会崩溃.这次,不执行推到列表前面的功能.

问题很简单:这是正确的吗?
为什么这两个例子如此违反直觉?

在第一种情况下,我期待不同的东西,我错了,这不是问题.
无论如何,我希望两个循环之间的一致性.我的意思是,第二个函数一个案例中执行,而在另一个案例中不执行,但我在两种情况下都是从开始到结束迭代.
我的推理出了什么问题?

解决方法

说实话,你得到的结果似乎是我的预期.让我们先看看你的第一个例子:

1.

list.push_back([&list](){ list.push_back([](){ throw; }); });

列表状态:

+-- list.begin() (not necessarily what has been passed to for_each)
v
[lambda]----[end]

2.开始迭代列表

迭代1:

列表状态:

+-- list.begin() (not necessarily what has been passed to for_each)
v
[lambda]----[end]
^
+-- current

f()调用list.push_back([](){throw;});

列表状态:

+-- list.begin() (not necessarily what has been passed to for_each)
v
[lambda]----[inner_lambda]----[end]
^
+-- current

迭代2 :(当前)

列表状态:

+-- list.begin() (not necessarily what has been passed to for_each)
v
[lambda]----[inner_lambda]----[end]
            ^
            +-- current

f()调用throw;

结束

现在让我们做另一个方向.

首先,看一下反向迭代器的实际表示方式 – 这很重要(来自cppreference的图像):

重要的部分是:反向终点指向正常开始.但问题是,使用列表,可以在开始之前插入一些内容,但是在结束之后不可能.反向迭代器打破了这个不变量.

1.

list.push_front([&list](){ list.push_front([](){ throw; }); });

列表状态:

+-- list.begin() (not necessarily what has been passed to for_each)
|
|+-- list.rend().base()
||
||          +-- list.rbegin().base()
vv          v
[lambda]----[end]

2.开始迭代列表

迭代1:

列表状态:

+-- list.begin() (not necessarily what has been passed to for_each)
|
|+-- list.rend().base()
||
||          +-- list.rbegin().base()
vv          v
[lambda]----[end]
    ^           ^
    |           +---- current
    |
    +--------- passed list.rend()

*当前产量λ.

f()调用list.push_front([](){throw;});

列表状态:

+-- list.begin() (not necessarily what has been passed to for_each)
|
|+-- list.rend().base()
||
||                            +-- list.rbegin().base()
vv                            v
[inner_lambda]----[lambda]----[end]
                      ^           ^
                      |           +---- current
                      |
                      +--------- passed list.rend().base()

请注意,传递的list.rend().base()没有更改 – 但它不再指向第一个(过去最后一个反转)元素.

迭代2 :(当前)

+-- list.begin() (not necessarily what has been passed to for_each)
|
|+-- list.rend().base()
||
||                            +-- list.rbegin().base()
vv                            v
[inner_lambda]----[lambda]----[end]
                      ^  ^
                      |  +---- current
                      |
                      +--------- passed list.rend().base()

current ==传递list.rend().base()

结束

现在让我们尝试另一个错误,这部分与前导迭代列表相关:

1.

list.push_front([&list](){ list.push_front([](){ throw; }); });

列表状态:

+-- list.begin() (not necessarily what has been passed to for_each)
v
[lambda]----[end]

2.开始迭代列表

迭代1:

列表状态:

+-- list.begin() (not necessarily what has been passed to for_each)
v
[lambda]----[end]
^
+-- current

f()调用list.push_front([](){throw;});

迭代器到当前不会失效和/或指向其他位置,而不是指向它.

列表状态:

+-- list.begin() (not necessarily what has been passed to for_each)
v
[inner_lambda]----[lambda]----[end]
                  ^
                  +-- current

迭代2 :(当前)

列表状态:

+-- list.begin() (not necessarily what has been passed to for_each)
v
[inner_lambda]----[lambda]----[end]
                              ^
                              +-- current

结束

相关文章

对象的传值与返回说起函数,就不免要谈谈函数的参数和返回值...
从实现装饰者模式中思考C++指针和引用的选择最近在看...
关于vtordisp知多少?我相信不少人看到这篇文章,多半是来自...
那些陌生的C++关键字学过程序语言的人相信对关键字并...
命令行下的树形打印最近在处理代码分析问题时,需要将代码的...
虚函数与虚继承寻踪封装、继承、多态是面向对象语言的三大特...