C++ 람다 mutable - C++ lamda mutable

Example

By default, the implicit operator() of a lambda is const. This disallows performing non-const operations on the lambda. In order to allow modifying members, a lambda may be marked mutable, which makes the implicit operator() non-const:

int a = 0;

auto bad_counter = [a] {
    return a++;   // error: operator() is const
                  // cannot modify members
};

auto good_counter = [a]() mutable {
    return a++;  // OK
}

good_counter(); // 0
good_counter(); // 1
good_counter(); // 2

C++ 람다 mutable - C++ lamda mutable
PDF - Download C++ for free



Previous Next

Intro

The variables captured by value (or copy) cannot be modified in a lambda expression by default. Let's take an example of a lambda that captures two variables, one by value and the other by reference from its outer scope:

void spam() {
 int v = 0, r = 0;
 auto l = [v, &r]() { //Capture v by value and r by ref
   v++; //ERROR
   r++; //OK
 };
 l();
}

As shown above, it is an error to modify a variable that is captured by value, but a variable captured by reference can be modified in the lambda. A lambda expression is essentially a function object with an overloaded function-call operator (operator ()). That overloaded function-call operator is const by default. Here is the above code with an equivalent custom function object:

struct Lambda {
 Lambda(int v_, int& r_)
  :v(v_),r(r_){}

 //overloded const function-call operator
 void operator()() const { // 'const'
   v++; //ERROR
   r++; //OK
 }
 int v;
 int& r;
};

void spam() {
  int v = 0, r = 0;
  Lambda l(v, r);
  l();
}

However, this default behavior can be overridden by the mutable qualifier. A mutable lambda expression is allowed to change the variables that are captured by value. A mutable lambda expression is equivalent to a function object with a non-const overloaded function-call operator. As an example, foo is a mutable lambda expression that can modify the value-captured variable x:

int x = 0;
auto foo = [x] () mutable { 
 /* "x" cannot be modified without 
      keyword mutable. */
 x++; //OK
 return x;
};

Mutable Lambda as Stateful Function Object

It might not be obvious that mutable lambda expressions are like stateful function objects. The captured variable x is the state of foo, which is changed every time foo is called. Consider the following code to see what is so interesting about it:

 // call foo
std::cout << foo() << " ";

// assign foo to bar
auto bar = foo;

// call foo again
std::cout << foo() << " ";

// call bar
std::cout << bar() << " ";

In brief, we call foo and then assign it to another variable bar, and then we call foo (again) followed by a call to bar. What would be the output of the above? Select the correct answer below (check the Explanations for details):

06 Aug 2017

This post is in continuation to Lambdas in C++.

Till now we covered basics of functors and lambdas in C++. We will cover Mutable lambdas in this post.

Mutable Lambdas

Object captured in lambda are immutable by default. This is because operator() of the generated functor (compiler generates functional object for lambdas) is const by default. Consider below C++ code:

#include<iostream>

int main(){
   int a=10;
    auto lam = [a](){a;};
    lam();
    return 0;
}

Assembly code for lambda lam generated by gcc 4.9.4 is:

main::{lambda()#1}::operator()() const:
  push rbp
  mov rbp, rsp
  mov QWORD PTR [rbp-8], rdi
  pop rbp
  ret

As you can see that const keyword is present in generated functor of lambda main::{lambda()#1}::operator()() const. This const prevent us from modifying objects in lambda captured by value.

int a=10;
auto lam = [a](){a++;}; //Compilation error 

Using mutable keyword allows us to mutate objects captured by value too.

int a=10;
auto lam = [a]() mutable {a++;};

If we see the assembly code for same code the generated functor after adding mutable keyword looks like:

main::{lambda()#1}::operator()()

We can clearly see that const is no longer present now. So adding mutable keyword makes operator() non-const.

In general lambda declaration mutable keyword comes before return-type

auto func = [a]() mutable -> int {++a; std::cout << a; return a;};

That’s it for mutable lambdas. I think we covered basics of lambdas. We will start with R-value reference from next blog post.

Till then Sayonara.