#keywords C++, Modern C++, 람다 {{{+2 람다 캡처란? }}} 정의: 람다를 선언할 때 [] 안에 캡처할 변수들을 명시한다. C++에서 람다(lambda)를 사용할 때 "캡처(capture)"는 변수들을 람다 바디에서 사용할 수 있도록 람다 함수 안으로 "가져오는 것"이다. {{{#!gcode int x = 10; auto f = [x]() { // x를 값으로 캡처 std::cout << x << std::endl; }; auto g = [&x]() { // x를 참조로 캡처 std::cout << x << std::endl; }; }}} * [[code([x])]]는 값(value) 캡처 → 복사본을 가짐 * [[code([&x])]]는 참조(reference) 캡처 → 원본을 참조 * [[code([=])]]은 모든 외부 변수를 값으로 * [[code([&])]]는 모든 외부 변수를 참조로 예시) {{{#!gcode void example() { auto block = [&]() { if (someCondition) { return; } doSomething(); }; block(); // 람다 실행 // 함수의 나머지 로직 doSomethingElse(); } }}} 그리고 캡처 자체는 성능 부담이 거의 없다. 그 이유는, {{{+1 성능 부담이 거의 없는 이유 }}} 람다는 내부적으로는 익명 클래스 객체로 변환되며, 캡처된 변수들은 해당 객체의 멤버로 저장된다. 예를 들어, {{{#!gcode int a = 5; auto lam = [a]() { return a * 2; }; }}} 이건 대충 다음과 같은 구조로 변환된다. {{{#!gcode struct __Lambda { int a; // 캡처한 변수 int operator()() const { return a * 2; } }; __Lambda lam = {5}; }}} 값 캡처는 단순히 멤버 변수로 복사 저장되고 참조 캡처는 포인터처럼 원본을 참조한다. 그래서 캡처 자체는 지역 변수 복사 or 포인터 저장이므로 CPU 비용이나 메모리 오버헤드가 매우 낮다. 람다는 일반적으로 인라인 함수로 처리되며, 최적화에 유리하다. {{{+2 예외적으로 성능 고려가 필요한 경우}}} 람다 캡처가 부담이 될 수 있는 특수한 상황: 1. 큰 객체를 값으로 캡처할 때 {{{#!gcode std::vector bigVec(1000000); auto lam = [bigVec]() { /* ... */ }; // 복사됨 }}} → 큰 객체를 값으로 캡처하면 복사 오버헤드가 발생한다. 이 경우에는 참조 캡처로 바꾸는 것이 좋다. 예) [[code([&bigVec])]] 2. std::function에 람다 저장할 때 {{{#!gcode std::function f = [a, b]() { /* ... */ }; }}} [[code(std::function)]]은 타입 소거(type-erased) wrapper이므로 내부적으로 heap 할당이 발생할 수 있다. → 해결 방법: 가능하면 auto로 람다를 직접 사용할 것, or std::function 사용을 최소화