2014-02-06 2 views
1

C++의 경우와 달리 C#과 같은 언어에서는 범위 변수를 값으로 캡처하거나 람다 식 내에서 참조로 캡처해야하는지 여부를 지정할 수 있습니다. 이는 람다 식 호출하기 전에 반환하는 함수를 참조하여 촬상 클로징 범위와 람다 전달하는 것이 가능하는 미정 경우 리드이 경우C++ 11 : 람다 범위 캡처 버그 방지

void test() 
{ 
    int t = 1; 
    enqueue_task([&]() { do_something(t); }); 
} 

를 "t"가장 가능성이있을 것 범위를 벗어난 경우 람다 식으로 지정된 작업이 실행되도록 예약됩니다. 분명히 추한 벌레가 생깁니다.

template<class T> 
void enqueue_task(T lambda) 
{ 
    static_assert(!std::is_lambda<T>::value || std::is_lambda_captured_by_value<T>::value, 
     "The lambda expression is executed asynchronously and therefore capturing eclosing state via reference is forbidden."); 

    // enqueue task for execution 
} 

이 나에게,이 미들웨어 작가 오용에서 자신의 API를 보호 할 수 있도록 해주는 깨끗한 "비 침습적"확장 될 것이다 :

MY 솔루션은이 같은 언어 기능이 될 것입니다. 물론 스택 객체에 대한 포인터를 값으로 전달할 수 있기 때문에 방탄 (bullet-proof) 보호 기능을 제공하지는 않습니다. 어쨌든 값으로 전달 될 때 정의되지 않은 동작을 조용히 일으키는 코드는 아마도 그 자체로 이미 의문의 여지가 있습니다.

내가 이미 할 수있는 비슷한 기능이 이미 지원됩니까?

저에게있어, 현명한 해결책은 지연된 실행 상황에서 람다 표현을 허용하지 않는 것 같습니다. 예를 들어, 이벤트 핸들러는 람다 유형이 될 수 없습니다. 이 말은 std :: function을 사용할 수 없다는 것을 의미하고 좋은 함수 유형으로 돌아 가야하기 때문에 더 쉽게 말한 것입니다.

더 좋은 방법은 같은 키워드의 종류를 소개하는 것입니다 : 모든이 할 수있는 컴파일러를 의미하여, 전달 된 람다 함수가 지연 실행에 적합 할 것,해야 할 것

void test() 
{ 
    int t = 1; 
    enqueue_task(deferred() { do_something(t); }); 
} 

, 이는 그 포위 범위가 사라질 때를 의미합니다.

저는 C++ 11이 C++ 프로그래밍을 안전하게 만드는 데 많은 시간을 할애했다고 생각합니다. 이 람다는 당신이 아직 총을 겨누고있는 몇 안되는 장소 중 하나입니다. 그것의 다만 똑딱 거리는 timebomb.

+0

"현재 순간 솔루션은 지연 실행 상황에서 람다 표현을 허용하지 않는 것처럼 보입니다." 그런 다음 클로저를 형성 할 수있는 능력을 잃게됩니다. – JAB

+0

@ JAB : Ofc,하지만 표준 방식을 허용하지는 않지만 API 방식을 허용한다는 의미는 아닙니다. 따라서 람다가 API의 유용성에 기여하지 못하고 사용자가 API가 람다를 지연시킨 것을 잊어 버릴 가능성이 있다면이 API에 람다를 사용하면 안됩니다. API는 올바른 사용을 강제해야합니다. – thesaint

+0

사실 충분하지만 람다식이 걱정되는 문제를 해결할 수있는 유일한 방법은 아닙니다. 사용자가 범위를 벗어나는 참조를 포함하는 이상한 일을하는 비 λ 함수를 전달하면 어떻게됩니까? 아니면, 신이 금지 한 원시 포인터? 진정한 API의 올바른 사용을 강제하는 유일한 방법은 사용자가 어떤 종류의 입력도 제공하지 못하도록하는 것입니다 (그렇게하지 않아도 제약 설정 방법을 신중히 모르는 경우 오탐 (false positive)이 발생할 수 있습니다 여기서 유효한 매개 변수는 사용자가 요구하는대로 설정되지 않았기 때문에 거부됩니다. – JAB

답변

3

일반적으로 해결 방법은 값 [=]() {...}으로 캡처하는 것입니다.
실제 개체를 복사 할 수없는 경우 일반적으로 shared_ptr을 통해이 개체를 사용하는 것이 유리합니다.이 개체는 컨텍스트에 따라 값이 더 싸게 복사 할 수 있으며 호출자와 지연된 개체를 모두 공유 할 수 있습니다 람다는 그것을 독립적으로 사용합니다.

C++ 14에는 공유가 필요하지 않을 때 개체 복사의 성능 문제를 해결하는 이동 캡처 구문이 있어야합니다.

그렇지 않으면 by-ref 전달이 원하는 것입니다. 그리고 람다뿐만 아니라 C++의 모든 것과 마찬가지로 포인터와 참조를 전달하기 시작할 때 조심해야합니다.

+0

그래, JAB가 그 일을 일찍 말했지만, 단지 주석으로 만 알았음에도 불구하고 나는 이것을 anwser로 표시하고있다 : P. – thesaint

+0

@thesaint 그는 그 중 일부를 말했다. 여기서 중요한 부분은 IMO가 가치 포착입니다. 동일한 객체가 필요한 곳에는 shared_ptrs를 값으로 사용하십시오. shared_ptr은 원자 적 연산 때문에 일부 시나리오에서 복사하는 데 약간 비싸지 만, 캡쳐 단위의 의미 체계가 곧 나올 것이라고 언급 한 이유입니다. –

관련 문제