在存在异常的情况下使用for_each? std :: exception_list

时间:2019-03-13 07:12:09

标签: algorithm exception foreach c++17 undo

cppreference文档https://en.cppreference.com/w/cpp/algorithm/for_each 说:

  
      
  • 如果作为算法一部分调用的函数的执行引发异常,并且ExecutionPolicy是三个标准策略之一,则称为 std :: terminate 。对于任何其他ExecutionPolicy,该行为都是实现定义的。
  •   

我认为这意味着我不能立即使用for_each传递的函数,而期望捕获异常或与之相关的某些信息。

我期望使用异常的原因是,我可以部分撤消(还原)在for_each调用中所做的更改。 (也许有一个更好的算法)。

但是,偶然地,我发现了for_each的历史版本,据记录它具有不同的,更有趣的行为:

http://man.hubwiz.com/docset/C.docset/Contents/Resources/Documents/output/en/cpp/algorithm/for_each.html

  
      
  • 如果策略为std :: parallel_vector_execution_policy,则称为std :: terminate
  •   
  • 如果策略为std :: sequential_execution_policy或std :: parallel_execution_policy,则算法以包含所有未捕获的异常的std :: exception_list退出。如果只有一个未捕获的异常,则算法可以将其重新抛出而无需包装在std :: exception_list中。在遇到第一个异常后返回之前,算法将执行多少工作尚未确定。
  •   

这似乎暗示着代替terminate的使用,实际上有可能使用异常。

那么,为什么std::exception_list被淘汰?争议性,复杂性(内存)成本太高?

即使我同意逻辑,我实际上也没有其他选择,因为并行for_each返回void(而不是返回UnaryFunction,这也很令人惊讶)。 因此, 在我看来,此std::exception_list协议似乎是撤消未能完成的for_each指令的必要组成部分。

期待某些新的自定义政策(例如, par_with_failed_list将会出现在允许进行undo的位置。


更多上下文:这种撤消失败循环的模式用于构造容器。我想实现一个自定义(并行/顺序)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

1 个答案:

答案 0 :(得分:1)

std::exception_list在并行算法的规范和实现中增加了很多复杂性,而没有太大的好处。

作为用户,您可以在函子中处理这种情况:

struct exception_info{
    ElementType* element;
    std::exception_ptr exception;
};
std::vector<exception_info> exceptions;
std::mutex exceptions_mutex;

std::vector<ElementType> range=...;

std::for_each(std::execution::par,range.begin(),range.end(),[&](ElementType& element){
    try{ do_stuff(element); }
    catch(...){
        std::lock_guard guard(exceptions_mutex);
        exceptions.push_back({&element,std::current_exception()});
    }});

exceptions列表现在将包含指向引发异常和引发异常的元素的指针列表。