在lambda运行之前,是否可以使lambda捕获的[this]指针无效?

2022-03-16 00:00:00 lambda this c++

假设我们有一个包含一些对象的STL容器,这些对象可以将函数发布到队列中,以便稍后执行。但是在执行这些函数之前,会修改容器,使指向该对象的指针无效。让我举一个例子来说明:

#include <vector>
#include <functional>
class Class_A
{
public:
    std::function<void()> getFunctionToRunLater()
    {
        return [this] () { somethingToDo(); moreThingsToDo(); };
        // Returns a lambda function that captures the this pointer,
        // so it can access the object's methods and variables.
    }

    void somethingToDo();
    void moreThingsToDo();
}

int main()
{
    std::vector<Class_A> vec;
    vec.push_back(Class_A());

    std::function<void()> pendingFunction = vec.back().getFunctionToRunLater();

   // More code...

   pendingFunction();
}

一切都好,对吧?我们得到一个对象想要运行的函数,在一些逻辑之后,我们执行该函数。这表示将函数发送到队列,并且它们执行队列中的所有函数。但现在看看这个:

int main()
{
    std::vector<Class_A> vec;
    vec.push_back(Class_A());

    std::function<void()> pendingFunction = vec.back().getFunctionToRunLater();

   // More code...

   vec.reserve(1000);
   // This will surely reallocate the vector, invalidating all pointers.

   pendingFunction();
   // And now my program is going straight down to hell, right?
}

我的假设正确吗?如果lambda根本没有捕捉到任何东西,那么会发生什么情况呢?程序在逻辑上还是会崩溃吗?如果lambda没有捕获this指针,而是专门捕获了一些其他类字段,该怎么办呢?


解决方案

existing answer已经提到指针可以失效。如前所述,避免该问题的一种方法是将*this的所有权更改为shared_ptrunique_ptr或副本。但是,这会带来额外成本(动态分配或额外复制),有时根本不可能(不可复制类型)。

相反,我会建议一种从一开始就不会导致此问题的设计,即不将this指针作为lambda状态的一部分。将对象作为参数:

std::function<void(Class_A&)> getFunctionToRunLater()
{
    return [] (Class_A& obj) { obj.somethingToDo(); obj.moreThingsToDo(); };
}

相关文章