2015-06-13 2 views
0

Я хочу иметь возможность совместно использовать переменную в области содержимого между двумя лямбда-функциями. У меня есть следующие:Поделиться переменной между двумя lambdas

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, чем во 2-й лямбда-функции.

Если я использую [=, &identifierCollection], он выбрасывает EXC_BAD_ACCESS, пользуюсь ли я mutable или нет.

Опыт работы с другими языками, реализующими встроенные функции, заключается в том, что это должно быть возможно. Например, в JavaScript:

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

предупредит ли 15.

Что мне нужно сделать, чтобы обе лямбда-функции ссылались на один и тот же идентификатор реализации набора? Таким образом, он ведет себя так же, как пример javascript.

+1

Таким образом, проблема заключается в том, что при захвате по значению, которое вы захватили по значению, и когда вы захватываете по ссылке, вы захватили оборванную ссылку на локальную переменную ... Вам нужно будет решить что вы хотите, чтобы жизнь объекта была. –

+1

делает '[&]' работа? попробуйте сделать карту 'static' – twentylemon

+2

Оберните карту в' shared_ptr'. –

ответ

4

В отличие от некоторых языков сценариев, срок службы identifierCollection не будет распространяться просто потому, что вы захватили его в закрытие. Итак, как только вы измените это значение [=] на [&], чтобы зафиксировать по ссылке, это болтается ссылкой на локальную переменную, которую вы захватываете.

Ты должен управляться жизнью identifierCollection; откровенно говоря, это звучит как прекрасная возможность для общего указателя, захваченного значением в каждую лямбду. Динамически распределенная карта, которую она обертывает, будет буквально существовать столько, сколько вам нужно.

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

Работает как ожидалось сейчас. Brilliant! Спасибо :) – richardjsimkins

+0

Хотя JavaScript не является языком сценариев, несмотря на его название;) Я бы сказал, что это скорее симптом C++, не имеющий сборку мусора. Поэтому я думаю, было бы лучше, если бы ответ сказал: «В отличие от языков, на которых есть сбор мусора», – richardjsimkins

2

Если вы завернете карту в std::shared_ptr, тогда управление временем будет автоматически. Затем ваша лямбда может захватываться по значению, и она получит ссылку на карту, чье жизненное время остается действительным до тех пор, пока функция лямбда не вернется.

Чтобы сделать это, измените определение карты для:

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

И тогда любые вызовы функций членов карты необходимо изменить с помощью . к -> (как это теперь указатель).

Смежные вопросы