Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ lambda ´this´ pointer invalidation after move operation

Tags:

c++

lambda

move

I have the following (simplified) code in my current project:

#include <iostream>
#include <string>
#include <functional>
#include <vector>


class Test{

public:

    Test() = default;
    Test(const Test& other) = delete;
    Test& operator=(const Test& other) = delete;
    Test(Test&& other) = default;
    Test& operator=(Test&& other) = default;



    void setFunction(){
       lambda = [this](){
           a = 2;
       };
    }  

    int callAndReturn(){
       lambda();
       return a;
    }

private:
    std::function<void()> lambda; 
    int a = 50;
};


int main()
{
  Test t;
  t.setFunction();
  std::vector<Test> elements;
  elements.push_back(std::move(t));
  std::cout << elements[0].callAndReturn() << std::endl;
}

When I run it, the value 50 is printed instead of the expected value 2. I suppose this happens because the lambda function captures the current this pointer. After the move operation the this pointer changes and the function writes to the wrong a.

Now my question is: Is there a way to change the lambda's captured reference to the new Test so that the value 2 is printed?

like image 665
Overblade Avatar asked Jun 25 '17 10:06

Overblade


People also ask

What happens if a lambda function becomes invalid?

If the lambda out lives the lifetime of the object that created it, the lambda can become invalid. This also means that the lambda can modify this without being declared mutable. It is the pointer which is const, not the object being pointed to. That is, unless the outer member function was itself a const function.

Why do we use lambda expressions instead of function pointers?

As the tasks performed by using function pointers are very small, hence it is not worth writing so many lines of code. Thus, Lambda expressions make it easier to do the same job. A Lambda expression is also called an anonymous function.

How do you capture this pointer in lambda function?

Lambdas can capture the this pointer which represents the object instance the outer function was called on. This is done by adding this to the capture list: When this is captured, the lambda can use member names of its containing class as though it were in its containing class. So an implicit this-> is applied to such members.

What is the use of Lambda in C++?

Such a lambda is not only a friend of that class, it has the same access as the class it is declared within has. Lambdas can capture the this pointer which represents the object instance the outer function was called on. This is done by adding this to the capture list:


1 Answers

The solution is not to capture this at all. Instead, change your captured function type to accept it. And use a pointer to member (captured by value) for the indirect access to a.

std::function<void(Test*)> lambda; 

void setFunction(){
   auto a = &Test::a;
   lambda = [=](Test *t){
       (t->*a) = 2;
   };
}  

int callAndReturn(){
   lambda(this);
   return a;
}

Live Example


As Galik noted, if you only need to access a single hard-coded member, then you don't even need that pointer to member. Thus the lambda can be capture-less:

void setFunction(){
   lambda = [](Test *t){
       t->a = 2;
   };
}  
like image 100
StoryTeller - Unslander Monica Avatar answered Sep 23 '22 17:09

StoryTeller - Unslander Monica