C++ Basics: Introdução ao lambda e uma breve descrição das diferenças e precauções para captura de valor, captura de referência e captura implícita

C++11 introduziu expressões lambda, que são uma maneira conveniente de definir e usar objetos de função anônimos. Uma expressão lambda é semelhante a uma função normal, pois também possui uma lista de parâmetros, um tipo de valor de retorno e um corpo de função, exceto que é definida de forma mais concisa e pode ser definida dentro de uma função.

A sintaxe de uma expressão lambda é a seguinte:

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

em:

  • capture É a lista de captura, que especifica quais variáveis ​​externas podem ser usadas no corpo da função lambda.
  • parameters é uma lista de parâmetros, semelhante à lista de parâmetros de uma função normal.
  • return_type é o tipo de valor de retorno, que pode ser omitido e inferido pelo compilador.
  • function_body É o corpo da função, que contém a lógica específica da função lambda.

Primeiro, olhe para esta pergunta da 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;

O resultado desta questão é 19 19 10 10.
A captura de referência transfere a referência, e a referência também mudará depois que o valor for modificado posteriormente. A captura de valor transfere o valor neste momento e a modificação subsequente não afeta o valor atual.

Existem três maneiras de especificar captura de valor, captura de referência e captura implícita na lista de captura:

  • Captura de valor: capture variáveis ​​externas por valor e use uma cópia da variável externa dentro da função lambda. Por exemplo,  [x] significa capturar variáveis ​​externas por valor  x. Abaixo está um exemplo:
#include <iostream>
int main() {
    int x = 10;
    auto f = [x]() { std::cout << x << std::endl; };
    x = 20;
    f(); // 输出 10
    return 0;
}

No código acima, capturamos a variável externa por valor  xe exibimos seu valor dentro da função lambda. Como é capturado por valor, mesmo que  x o valor seja modificado posteriormente, o valor original ainda é usado dentro da função lambda.

  • Captura de referência: as variáveis ​​externas são capturadas por referência e as próprias variáveis ​​externas são usadas dentro da função lambda. Por exemplo,  [&x] significa capturar variáveis ​​externas por referência  x. Abaixo está um exemplo:
#include <iostream>
int main() {
    int x = 10;
    auto f = [&x]() { std::cout << x << std::endl; };
    x = 20;
    f(); // 输出 20
    return 0;
}

No código acima, capturamos a variável externa por referência  xe exibimos seu valor dentro da função lambda. Como é capturado por referência, quando  x o valor for modificado posteriormente, o novo valor também será utilizado dentro da função lambda.

  • Captura implícita: você pode usar  & ou  = para especificar a captura implícita de todas as variáveis ​​externas. Por exemplo,  [&] significa que todas as variáveis ​​externas são capturadas implicitamente por referência [=] e todas as variáveis ​​externas são capturadas implicitamente por valor. Abaixo está um exemplo:
#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;
}

No código acima, definimos duas funções lambda usando captura de referência implícita e captura de valor implícito, respectivamente. x Quando o valor de e  é modificado posteriormente  y , a primeira função lambda gera o novo valor, enquanto a segunda função lambda gera o valor original.

Deve-se observar que, ao usar a captura de referência, é necessário garantir que o objeto referenciado ainda exista quando a expressão lambda for executada. Além disso, ao modificar variáveis ​​locais não estáticas capturadas por valor em uma função lambda, palavras-chave precisam ser adicionadas após a lista de parâmetros  mutable .

As expressões lambda são muito flexíveis e poderosas, mas há alguns problemas a serem observados. Por exemplo,

  1. Preste atenção aos problemas de segurança do encadeamento ao usar a captura de referência em um ambiente multiencadeado;
  2. Tenha cuidado para não capturar acidentalmente variáveis ​​desnecessárias ao usar a captura implícita;
  3. Ao usar a captura de valor, preste atenção se a variável capturada pode ser copiada, etc.
    Concluindo, considere cuidadosamente várias situações ao usar expressões lambda para evitar problemas inesperados.

Guess you like

Origin blog.csdn.net/CHNIM/article/details/132278690