首页 > 解决方案 > 如果在一个地方多次使用 lambda 函数,应该将其设为本地还是全局

问题描述

从向量中删除元素的标准被定义为 lambda 函数,因为它没有在其他任何地方使用。现在如果 delete_data 定期执行,它必须每次都创建新的 lambda 实例。我们怎样才能使它的性能更好:

  1. 与其将标准定义为 lambda,不如将其定义为 delete_data() 之外的内联函数。

  2. 通过将 lambda 设为静态。

  3. 我们如何内联块级 lambda 以提高性能?

     struct SomeStruct
     {
         string id;
         int psx;
         /*other data */
     }
    
    
     shared_mutex my_mutex;
     vector<SomeStruct>v;
     void delete_data(vector<SomeStruct>&v, string const& id)
     {
         auto const delete_criteria {[=](SomeStruct const& d){return (d.id == id);}};
    
         unique_lock ul{my_mutex};
         v.erase(find_if(begin(v), end(v), delete_criteria));
     }
    

标签: c++c++17

解决方案


您的前两个选项不正确,最后一个选项不是必需的。让我们逐步分析它们。

与其将标准定义为 lambda,不如将其定义为 delete_data() 之外的内联函数。

的第三个参数find_if必须是一个可调用对象,它只有一个参数接受范围内的这些元素,这意味着,如果您定义一个函数,则只允许该元素类型的一个参数。你无法id在你定义的那个函数中获取。

通过将 lambda 设为静态。

那会犯错误。换句话说, 的值id永远不会在 lambda 的复合语句中改变。由于以下规则:

具有静态存储持续时间或线程存储持续时间的块范围变量的动态初始化在控制第一次通过其声明时执行;这样的变量在其初始化完成时被认为已初始化。如果初始化抛出异常退出,说明初始化未完成,下次控件进入声明时会再次尝试。

简单来说,对象的初始化delete_criteria只执行一次。重新进入函数delete_data,闭包类型对象delete_criteria仍保持原值。IE 中, 的值始终与函数第一次执行时的值id相同。delete_criteria所以,这是你的程序的一个错误。

好吧,考虑你问题中的最后一个选项

我们如何内联块级 lambda 以提高性能?

没有必要。因为闭包类型的函数调用运算符是 public inline 本身,如此处所述。

非泛型 lambda 表达式的闭包类型具有公共内联函数调用运算符,其参数和返回类型分别由 lambda 表达式的参数声明子句和尾随返回类型描述。对于通用 lambda,闭包类型有一个公共的内联函数调用运算符成员模板,其模板参数列表由一个发明的类型模板参数组成,用于 lambda 的参数声明子句中每次出现的 auto,按出现顺序。

我认为您只需要在这里更改=的是,将 lambda 表达式更改为&or &id。此更改将避免 lambda 表达式id通过copy捕获变量,相反通过引用。此更改还将使闭包类型成为文字类型。即使delete_criteria每次函数delete_data进入时都会评估初始化,但这样的初始化不会花费太多。


推荐阅读