Conceptos básicos de C++: Introducción a lambda y una breve descripción de las diferencias y precauciones para la captura de valor, la captura de referencia y la captura implícita

C ++ 11 introdujo expresiones lambda, que son una forma conveniente de definir y usar objetos de función anónimos. Una expresión lambda es similar a una función normal en que también tiene una lista de parámetros, un tipo de valor devuelto y un cuerpo de función, excepto que se define de manera más concisa y se puede definir dentro de una función.

La sintaxis de una expresión lambda es la siguiente:

[capture] (parameters) -> return_type { function_body }

en:

  • capture Es la lista de captura, que especifica qué variables externas se pueden usar en el cuerpo de la función lambda.
  • parameters es una lista de parámetros, similar a la lista de parámetros de una función normal.
  • return_type es el tipo de valor devuelto, que el compilador puede omitir e inferir.
  • function_body Es el cuerpo de la función, que contiene la lógica específica de la función lambda.

Primer vistazo a esta pregunta de la entrevista

    int v = 19;
    auto f1 = [v]{return v;};  // 值捕获
    auto f2 = [=]{return v;}; // 隐式捕获值

    auto f3 = [&v]{return v;}; // 引用捕获
    auto f4 = [&]{return v;};  // 隐式捕获引用

    v = 10;
    std::cout << f1() << " " << f2()  << " " << f3() << " " << f4() << std::endl;

El resultado de salida de esta pregunta es 19 19 10 10.
La captura de referencia transfiere la referencia, y la referencia también cambiará después de que el valor se modifique más adelante. La captura de valor transfiere el valor en este momento, y la modificación posterior no afecta el valor actual.

Hay tres formas de especificar captura de valor, captura de referencia y captura implícita en la lista de captura:

  • Captura de valor: capture variables externas por valor y use una copia de la variable externa dentro de la función lambda. Por ejemplo,  [x] significa capturar variables externas por valor  x. A continuación se muestra un ejemplo:
#include <iostream>
int main() {
    int x = 10;
    auto f = [x]() { std::cout << x << std::endl; };
    x = 20;
    f(); // 输出 10
    return 0;
}

En el código anterior, capturamos la variable externa por valor  xy generamos su valor dentro de la función lambda. Debido a que se captura por valor, incluso si  x el valor se modifica más adelante, el valor original aún se usa dentro de la función lambda.

  • Captura de referencia: las variables externas se capturan por referencia, y las propias variables externas se utilizan dentro de la función lambda. Por ejemplo,  [&x] significa capturar variables externas por referencia  x. A continuación se muestra un ejemplo:
#include <iostream>
int main() {
    int x = 10;
    auto f = [&x]() { std::cout << x << std::endl; };
    x = 20;
    f(); // 输出 20
    return 0;
}

En el código anterior, capturamos la variable externa por referencia  xy generamos su valor dentro de la función lambda. Dado que se captura por referencia, cuando  x el valor se modifique más tarde, el nuevo valor también se utilizará dentro de la función lambda.

  • Captura implícita: puede usar  & o  = para especificar la captura implícita de todas las variables externas. Por ejemplo,  [&] significa que todas las variables externas se capturan implícitamente por referencia [=] y todas las variables externas se capturan implícitamente por valor. A continuación se muestra un ejemplo:
#include <iostream>
int main() {
    int x = 10, y = 20;
    auto f1 = [&]() { std::cout << x << " " << y << std::endl; };
    auto f2 = [=]() { std::cout << x << " " << y << std::endl; };
    x = 30; y = 40;
    f1(); // 输出 30 40
    f2(); // 输出 10 20
    return 0;
}

En el código anterior, hemos definido dos funciones lambda utilizando la captura de referencia implícita y la captura de valor implícito, respectivamente. x Cuando el valor de y  se modifica posteriormente  y , la primera función lambda genera el nuevo valor, mientras que la segunda función lambda genera el valor original.

Cabe señalar que cuando se utiliza la captura de referencia, es necesario asegurarse de que el objeto al que se hace referencia todavía existe cuando se ejecuta la expresión lambda. Además, al modificar variables locales no estáticas capturadas por valor en una función lambda, se deben agregar palabras clave después de la lista de parámetros  mutable .

Las expresiones lambda son muy flexibles y poderosas, pero hay algunos problemas a tener en cuenta. Por ejemplo,

  1. Preste atención a los problemas de seguridad de subprocesos cuando utilice la captura de referencia en un entorno de subprocesos múltiples;
  2. Tenga cuidado de no capturar accidentalmente variables que no necesita al utilizar la captura implícita;
  3. Cuando utilice la captura de valor, preste atención a si la variable capturada se puede copiar, etc.
    En conclusión, considere cuidadosamente varias situaciones cuando use expresiones lambda para evitar problemas inesperados.

Supongo que te gusta

Origin blog.csdn.net/CHNIM/article/details/132278690
Recomendado
Clasificación