C++ Lambdas: Difference between "mutable" and capture-by-reference

C++C++11Lambda

C++ Problem Overview


In C++ you can declare lambdas for example like this:

int x = 5;
auto a = [=]() mutable { ++x; std::cout << x << '\n'; };
auto b = [&]()         { ++x; std::cout << x << '\n'; };

Both let me modify x, so what is the difference?

C++ Solutions


Solution 1 - C++

##What is happening

The first will only modify its own copy of x and leave the outside x unchanged. The second will modify the outside x.

Add a print statement after trying each:

a();
std::cout << x << "----\n";
b();
std::cout << x << '\n';

This is expected to print:

6
5
----
6
6

##Why

It may help to consider that lambda

> [...] expressions provide a concise way to create simple function objects

(see [expr.prim.lambda] of the Standard)

They have

> [...] a public inline function call operator [...]

which is declared as a const member function, but only

> [...] if and only if the lambda expression’s parameter-declaration-clause is not followed by mutable

You can think of as if

	int x = 5;
	auto a = [=]() mutable { ++x; std::cout << x << '\n'; };

==>

	int x = 5;

	class __lambda_a {
		int x;
	public:
		__lambda_a () : x($lookup-one-outer$::x) {}
		inline void operator() { ++x; std::cout << x << '\n'; }     
	} a;

and

	auto b = [&]()         { ++x; std::cout << x << '\n'; };

==>

	int x = 5;

	class __lambda_b {
		int &x;
	public:
		__lambda_b() : x($lookup-one-outer$::x) {}
		inline void operator() const { ++x; std::cout << x << '\n'; }         
		//                     ^^^^^
	} b;

Q: But if it is a const function, why can I still change x?

A: You are only changing the outside x. The lambda's own x is a reference, and the operation ++x does not modify the reference, but the refered value.

This works because in C++, the constness of a pointer/reference does not change the constness of the pointee/referencee seen through it.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSebastian MachView Question on Stackoverflow
Solution 1 - C++Sebastian MachView Answer on Stackoverflow