2015-06-13 291 views
0

我希望能够在两个lambda函数之间共享包含范围内的变量。我有以下几点:在两个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比第二拉姆达功能调试器看到的。

如果我使用[=, &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示例相同。

+1

所以问题是,当你按值捕获你已经捕获的价值,当你通过引用捕获你已经捕获了一个悬浮的引用本地变量....你必须决定你想要的对象的生命周期。 –

+1

有没有'[&]'工作?尝试使地图'静态' – twentylemon

+2

将地图包裹在'shared_ptr'中。 –

回答

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); 
} 
+0

现在按预期工作。辉煌!谢谢:) – richardjsimkins

+0

虽然JavaScript不是一种脚本语言,尽管它的名字;)我会说它更多的是没有垃圾回收的C++症状。所以我认为如果答案是“不同于有垃圾收集的语言” – richardjsimkins

2

如果您将地图封装在std::shared_ptr中,则会自动管理生命期。然后你的lambda可以通过值捕获,并且它将得到一个对其生命期一直保持有效的映射的引用,直到lambda函数返回。

要做到这一点,你的地图定义修改为:

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

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