在两个lambda之间共享变量

时间:2015-06-13 21:43:18

标签: c++ lambda anonymous-function capture

我希望能够在两个lambda函数之间的包含范围内共享变量。我有以下内容:

void holdAdd(const Rect& rectangle, Hold anonymousHeld, Hold anonymousFinish) {
    std::map<int,bool> identifierCollection;

    HoldFinish holdFinish = [=](const int& identifier) mutable {
        if (identifierCollection.count(identifier) == 0) return;

        identifierCollection.erase(identifier);
        anonymousFinish();
    };

    holdCollisionCollection.push_back([=](const int& identifier, const Vec2& point) mutable {
        if (rectangle.containsPoint(point)) {
            identifierCollection[identifier] = true;
            anonymousHeld();
        } else {
            holdFinish(identifier);
        }
    });
    holdFinishCollection.push_back(holdFinish);
}

我可以在调试器中看到holdFinish指向identifierCollection的不同实现,而不是第二个lambda函数。

如果我使用[=, &identifierCollection],则无论是否使用EXC_BAD_ACCESS,都会引发mutable

我使用其他语言实现内联函数的经验是,这应该是可行的。例如在javascript中:

var a = 10;
var b = function() {
    a += 2;
}
var c = function() {
    a += 3;
}
b();
c();
alert(a);

会提醒15

我需要做些什么才能让两个lambda函数引用相同的identifierCollection实现?因此它的行为方式与javascript示例相同。

2 个答案:

答案 0 :(得分:4)

与某些脚本语言不同,identifierCollection的生命周期不会因为您将其捕获到闭包中而被延长。因此,只要您将[=]更改为[&]以通过引用进行捕获,就会对您正在捕获的本地变量进行悬空引用。

您必须自己管理identifierCollection的生命周期;坦率地说,这听起来像是一个共享指针的绝佳机会,它被价值捕获到每个lambda中。只要你需要它,它包装的动态分配的地图就会存在。

void holdAdd(const Rect& rectangle, Hold anonymousHeld, Hold anonymousFinish)
{
    auto identifierCollection = std::make_shared<std::map<int,bool>>();

    HoldFinish holdFinish = [=](const int& identifier) mutable {
        if (identifierCollection->count(identifier) == 0) return;

        identifierCollection->erase(identifier);
        anonymousFinish();
    };

    holdCollisionCollection.push_back([=](const int& identifier, const Vec2& point) mutable {
        if (rectangle.containsPoint(point)) {
            (*identifierCollection)[identifier] = true;
            anonymousHeld();
        } else {
            holdFinish(identifier);
        }
    });
    holdFinishCollection.push_back(holdFinish);
}

答案 1 :(得分:2)

如果您将地图包裹在std::shared_ptr中,则会自动管理生命周期。然后,您的lambda可以按值捕获,它将获得对映射的引用,该映射的生存期在lambda函数返回之前保持有效。

要执行此操作,请将地图定义更改为:

auto identifierCollection = std::make_shared<std::map<int,bool>>();

然后对地图成员函数的任何调用都需要从使用.更改为->(因为它现在是指针)。