Main Content

MISRA C++:2023 Rule 8.1.1

A non-transient lambda shall not implicitly capture this

Since R2024b

Description

Rule Definition

A non-transient lambda shall not implicitly capture this.

Rationale

When a lambda attempts to implicitly capture member variables of a class by value ([=]) or by reference ([&]), it implicitly captures the this pointer. Consider this class:

class foo {

public:
	int data;

	void func() {
		auto lambda1 = [ = ]() {return data;};
		auto lambda2 = [ & ]() {return data;};
	}


};
The lambda expression lambda1 copies the this pointer to the lambda scope. The lambda expression lambda2 captures the this pointer by reference. Neither of these lambda expressions copies data or captures a reference to data in the scope of the lambda.

Implicitly capturing the this pointer instead of member variables can be unexpected, and can lead to a call to the lambda after the lifetime of this pointer ends. Calling a lambda with an expired pointer is undefined behavior.

A transient lambda cannot be called after the end of lifetime of the this pointer of its enclosing class. This rule does not apply to transient lambdas.

To avoid undefined behavior, avoid implicit capture of the this pointer. Instead, capture the this pointer explicitly.

Polyspace Implementation

Polyspace® reports a violation if all of these conditions are met:

  • A lambda is defined within a class or struct.

  • The lambda implicitly captures member variables by value ([=]) or by reference ([&]).

  • The lambda does not explicitly capture the this pointer.

Violations of this rule are not reported for transient lambdas. A lambda is transient if it is invoked immediately following its definition or if it is passed to a function that does not store it. For example, the lambda L1 is a nontransient lambda and the lambda L2 is a transient lambda.

auto L1 = [&](){/**/;}
auto L2 = [&](){/**/;}() //invoked immediately

Troubleshooting

If you expect a rule violation but Polyspace does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

In this example, the function SearchFor::is_query_in_Data uses two lambda functions as predicates for the algorithm std::find_if. When evaluating the iterator findElement, the predicate lambda captures the member variables by value, implicitly capturing the this pointer. Polyspace reports a violation of this rule.

#include <algorithm>
#include <array>
#include <string_view>
#include <string>

class SearchFor {
private:
	std::string query{};
	std::array<std::string_view, 2> Data{"Hello", "world"};
public:
	SearchFor(std::string s) : query(s) {}

	void is_query_in_Data() {

		auto findElement = std::find_if(Data.begin(), Data.end(),
		[ = ](std::string_view str) {              //Noncompliant
			return (str.find(query) != std::string_view::npos);
		});

		auto findElementExplicitCapture = std::find_if(Data.begin(), Data.end(),
		[this](std::string_view str) {            //Compliant
			return (str.find(query) != std::string_view::npos);
		});
		//...
	}
};

When evaluating the iterator findElementExplicitCapture, the lambda predicate for the find_if algorithm explicitly captures the this pointer, which is compliant.

Check Information

Group: Expressions
Category: Required

Version History

Introduced in R2024b