【发布时间】:2019-03-13 07:12:09
【问题描述】:
cppreference 文档https://en.cppreference.com/w/cpp/algorithm/for_each 说:
- 如果执行作为算法一部分调用的函数引发异常并且 ExecutionPolicy 是三个标准策略之一,则调用 std::terminate。对于任何其他 ExecutionPolicy,行为是实现定义的。
我解释这意味着我不能开箱即用地从 for_each 传递的函数中抛出并期望捕获异常或与之相关的一些信息。
我期望使用异常的原因是我可以部分撤消(还原)在for_each 调用中所做的更改。
(也许有更好的算法)。
但是,我偶然发现了 for_each 的历史版本,它被记录为具有不同的、更有趣的行为:
- 如果策略是 std::parallel_vector_execution_policy,则调用 std::terminate
- 如果策略是 std::sequential_execution_policy 或 std::parallel_execution_policy,算法以包含所有未捕获异常的 std::exception_list 退出。如果只有一个未捕获的异常,算法可能会重新抛出它,而不用包装在 std::exception_list 中。在遇到第一个异常后返回之前,算法将执行多少工作是未指定的。
这似乎暗示着实际上可能使用异常而不是terminateing。
那么,为什么std::exception_list被淘汰了?是不是太有争议,太复杂,太(内存)成本?
即使我同意这个逻辑,我也真的没有其他选择,因为并行 for_each 返回 void(而不是 UnaryFunction 返回,这也令人惊讶)。
所以,
在我看来,这个std::exception_list 协议是撤消未完成的for_each 指令的必要组件。
期待一些新的自定义政策是否合理,例如par_with_failed_list 将出现在允许undoing 的地方。
更多上下文:这种撤消失败循环的模式用于构建容器。我想实现一个自定义(并行/顺序)uninitialized_value_construct_n,当(任何未排序的)构造失败时,它会“撤消”(销毁)初始化的对象。
EDIT1:不过,也许可以将 lambda 中捕获的变量传递给函数参数。 此变量可以是共享并发数据,可以在异常发生时存储异常(作为 exception_list)。 我想知道这是否已经完成。
EDIT2:我在 HPX 中找到了 exception_list 的实现,
https://github.com/STEllAR-GROUP/hpx/blob/master/hpx/exception_list.hpp
https://github.com/STEllAR-GROUP/hpx/blob/master/src/exception_list.cpp
【问题讨论】:
-
那是p0394r4
标签: c++ exception foreach c++17 stl-algorithm