Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 76 di 93
  • livello avanzato
Indice lezioni

Qualificatore mutable per espressioni lambda

Nella definizione di espressioni lambda in C++, il qualificatore mutable rende possibile alterare il valore delle variabili catturate per valore.
Nella definizione di espressioni lambda in C++, il qualificatore mutable rende possibile alterare il valore delle variabili catturate per valore.
Link copiato negli appunti

Nel contesto della definizione delle espressioni lambda, il qualificatore mutable assume una valenza semantica particolare.

L'uso del qualificare mutable in questo contesto rende infatti possibile alterare il valore delle variabili catturate per valore nel corpo di istruzioni di una espressione lambda.

La sintassi è mostrata nella figura seguente, in cui il qualificatore, se presente, viene collocato subito dopo la lista di argomenti della espressione.

La cattura per valore, come discusso in precedenza, consente di catturare per copia una variabile dal contesto esterno alla espressione. Per default, tale copia è accessibile all'interno del corpo di istruzioni in sola lettura, ma non è modificabile.

Ciò consente di invocare la medesima espressione lambda più volte, senza il rischio di alterare i valori catturati in origine dal contesto esterno tra un esecuzione e l'altra.

La cattura per riferimento, invece, consente di alterare liberamente le variabili catturate dall'esterno. Come conseguenza di ciò, a seguito dell'esecuzione dell'espressione lambda, il contesto di invocazione risulta alterato.

Un esempio di questo comportamento è riportato nel listato seguente:

#include <iostream>
int main()
{
    int num1 = 0;    
    auto lambda_Capture_By_Ref = [&num1] () -> int {
        // L'alterazione di num1 è possibile per effetto della cattura per riferimento.
        // Catturando num1 per valore, l'istruzione num1++ darebbe luogo ad un errore di compilazione.
        return num1++;
    };
    std::cout << "Lambdas with capture by reference" << std::endl;
    for (int i=0; i<5; i++)
        std::cout << lambda_Capture_By_Ref() << "\n";
    // Il valore di num1 nel contesto di origine è cambiato.
    std::cout << "Num1: " << num1 << std::endl; 
    return 0;
}

Il quale produce il seguente output:

Lambdas with capture by reference
0
1
2
3
4
Num1: 5

A seconda dei casi, l'alterazione del contesto esterno può essere un effetto collaterale innocuo oppure potenzialmente pericoloso per la stabilità del programma.

In questi casi, l'uso del qualificatore mutable consente di catturare per valore variabili esterne e di modificare liberamente il valore della copia catturata nel corpo di istruzioni. In pratica, le alterazioni prodotte dal corpo della espressione lambda persistono tra un'esecuzione e l'altra, ma non hanno effetti nel contesto esterno.

Nel listato seguente, il corpo di istruzioni della lambda risulta inalterato rispetto l'esempio precedente.

#include <iostream>
int main()
{
    int num1 = 0;    
    // mutable lambda
    auto mutable_lambda_Capture_By_Value = [num1] () mutable -> int {
        // L'alterazione di num1 è possibile per effetto del qualificatore mutable
        return num1++;
    };
    std::cout << "Mutable lambdas with capture by value" << std::endl;
    for (int i=0; i<5; i++)
    {
        // Il valore della copia di num1 catturata dalla lambda, è incrementato ad ogni iterazione.
        std::cout << mutable_lambda_Capture_By_Value() << "\n";
    }
    // Ma il valore di num1 non è cambiato.
    std::cout << "Num1: " << num1 << std::endl; 
    return 0;
}

In effetti, analizzando l'output del programma, le molteplici invocazioni dell'espressione producono la medesima sequenza di numeri. Tuttavia, a differenza del caso precedente, l'uso della cattura per valore unitamente al qualificatore mutable lasciano immutato il contesto esterno.

Mutable lambdas with capture by value
0
1
2
3
4
Num1: 0

La variabile num1 originale non è infatti soggetta a nessuna alterazione, visto che è stata catturata per copia.

Con l'aggiunta di questo componente, la sintassi delle espressioni lambda consente quindi di particolarizzare l'uso della modalità di cattura per valore al fine di implementare una sorta di gestione dello stato interno della lambda, che non ha ripercussioni sull'ambiente esterno ad essa.

Si ricordi che, in effetti, l'uso di espressioni lambda è sostanzialmente una sintassi concisa per implementare dei funtori. In questo senso, le variabili catturate sono come membri privati di classe usati per immagazzinare copie o riferimenti a variabili esterne.

In termini non rigorosi, possiamo quindi equiparare le variabili catturate per copia a membri di classe decorati per default con il qualificatore const.

Il qualificatore mutable applicato alla definizione di un'espressione lambda consente di cambiare questo comportamento predefinito.

In pratica, decorando una lambda con mutable stiamo indicando in maniera esplicita che il suo stato, inteso come insieme delle variabili catturate per valore dall'esterno, può evolversi per effetto delle istruzioni presenti nel corpo della lambda, senza tuttavia produrre effetti collaterali nel mondo esterno.

Ti consigliamo anche