2017-09-20 1 views
9
#include <iostream> 
#include <algorithm> 
#include <vector> 

int main() 
{ 
    // Block 1 
    { 
    auto inc = []() { int i = 0; return [&]() { return i++; }; }(); 
    std::vector<int> v(10, 10); 
    std::generate(v.begin(), v.end(), inc); 
    for (auto i : v) std::cout << i << std::endl; 
    } 

    // Block 2 
    { 
    auto inc = []() { int i = 0; return [&]() { return i++; }; }; 
    std::vector<int> v(10, 10); 
    std::generate(v.begin(), v.end(), inc()); 
    for (auto i : v) std::cout << i << std::endl; 
    } 
} 

왜 두 블록이 다른 결과를 생성하는지 잘 모르겠습니다. 람다를 사용하는 C++ 클로저

Block 1: 32767 ... 32776 
Block 2: 0 ... 10 

그리고 std::generate 발전기 (inc) 값에 의해 전달, 그래서 그것을 바로 괜찮을 것으로 판단됩니다에 대한

? 나는 OS X의에게

감사를 실행하고

, 코드 위의 결과는 정의되지 않은 것을


참고, 아래를 참조하십시오.

+0

gcc v5.1.0은 두 경우 모두 동일한 출력을 생성합니다. – Slava

+0

clang 버전 3.6.2로 컴파일 중입니다. – Ling

+1

신경 쓰지 마라. 그것은 UB 다. 그래서 특별한 출력은 무의미하다. – Slava

답변

10

왜 두 블록이 다른 결과를 생성하는지 잘 모르겠습니다.

두 가지 모두 정의되지 않은 동작이므로 질문은 중요하지 않습니다.

auto f = []() { int i = 0; return [&]() { return i++; }; }; 

그리고 f() 반환 매달려 참조가 람다 : if에 대한 호출의 끝에서 파괴 각각의 경우에, 우리는 람다 등이 있습니다. generate() 전화 또는 generate() 전화가 오기 훨씬 전에 발생했는지 여부는 일 때 일 때 아무런 의미가 없습니다. 당신은 람다와 생성 카운터를 확인하려면

는 직접적인 방법은 람다 가변 및 사용 초기화 캡처하는 것입니다 : 람다 기본적으로 const이기 때문에

auto inc = [i=0]() mutable { return i++; }; 

mutable이 필요합니다, 그리고 회원 i을 직접 수정해야합니다.


위의 내용은 C++ 14 (일반화 된 init 캡처로 인해)입니다. 우리는 값으로 촬영에 C++ (11) 단순히 참조하여 내부 람다 캡처에서 중첩 된 람다 구조를 변경하여이 작업을 할 수 있습니다 :

auto inc = []{ int i = 0; return [=]() mutable { return i++; }; }(); 
//        ~~~ ~~~~~~~ 

의 ... 불쾌한 종류의,하지만 작동?

+0

[i = 0]에 C++ 14가 필요합니까? – Slava

+0

@Slava 예, OP의 원래 중첩 된 - 람다 예제를 C++ 11에서 여전히 작동하도록 수정하는 방법을 추가했습니다. – Barry

+0

감사합니다.'i'는 람다가'struct'처럼 생각되면'operator()'내부의 로컬 임시 객체입니다. 따라서 반환 된 람다가 캡처하는 것은 지역 변수에 대한 잘못된 참조입니다. 그렇기 때문에 두 경우 모두 UB입니다. 처음에는 진짜 폐쇄처럼 행동 할 것이라고 생각했습니다. – Ling

관련 문제