이 레슨과 관련된 학습 키워드
컴퓨터 과학 & 프로그래밍 — 문제 해결의 도구 → C++ 프로그래밍 — 성능과 추상화의 균형 → C++ 프로그래밍 — 성능과 추상화의 균형 → 실전
Lambda syntax, capture, std::function, closures, higher-order functions, STL integration, generic lambda.
오늘은 C++에서 Lambda가 왜 필요한지 알아보겠습니다.
Lambda는 이름 없는 함수 객체를 즉석으로 정의하는 문법입니다.
C++ 11에서 처음 도입되어 이후 버전에서 계속 강화되었습니다.
그림 상단 왼쪽을 보시면 C 스타일 함수 포인터가 나옵니다.
함수 포인터는 주변 변수를 캡처할 수가 없습니다.
상태 전달에 void 포인터가 필요해서 타입 안전성이 무너집니다.
가운데 박스를 보시면 C++ 03의 Functor 방식이 있습니다.
struct 안에 operator()를 정의하는 방법입니다.
상태 캡처는 가능하지만 보일러플레이트 코드가 너무 많습니다.
3줄짜리 로직에 클래스를 통째로 만드는 비효율이 생기죠.
오른쪽 박스를 보시면 C++ 11 Lambda가 등장합니다.
한 줄로 간결하게 쓸 수 있고 인라인 최적화도 가능합니다.
선언과 사용이 한 곳에 있으니 코드 가독성도 크게 높아집니다.
이제 Lambda 문법을 직접 해부해 보겠습니다.
그림 중간 부분을 보시면 Lambda 식 전체가 크게 표시됩니다.
맨 앞 대괄호 부분이 캡처 리스트입니다.
등호는 모든 변수를 값으로 복사하고, 앰퍼샌드는 참조 캡처입니다.
그 뒤 괄호 안은 일반 함수와 같은 매개변수 목록입니다.
화살표 다음 반환 타입은 생략할 수도 있습니다.
마지막 중괄호 안이 실제 실행될 함수 본문입니다.
캡처 모드 비교를 보면, 빈 대괄호는 캡처 없음을 뜻합니다.
혼합 캡처나 this를 이용한 멤버 접근도 지원합니다.
그림 하단을 보시면 컴파일러가 Lambda를 어떻게 변환하는지 나옵니다.
컴파일러는 Lambda를 익명 클로저 클래스로 변환합니다.
캡처된 변수는 클래스 멤버 필드가 되고, 본문은 operator() 메서드가 됩니다.
인라인 최적화 덕분에 함수 호출 오버헤드가 제로입니다.
실전에서 Lambda는 STL 알고리즘과 잘 어울립니다.
std::sort, std::find_if 등에 즉석 콜백을 넘길 수 있습니다.
C++ 14부터는 auto 매개변수로 Generic Lambda도 쓸 수 있습니다.
C++ 17의 constexpr Lambda는 컴파일 타임 계산에도 활용됩니다.
선생님: 여기서 질문이 하나 들어왔네요.
학생: 선생님, 값 캡처 [=]랑 참조 캡처 [&]는 실제로 어떻게 다른 건가요?
선생님: 좋은 질문이에요! 값 캡처는 람다를 만드는 순간 변수의 복사본을 찍어두는 거예요.
선생님: 사진 찍듯이 그 시점 값을 보관해서, 나중에 원본이 바뀌어도 람다는 몰라요.
선생님: 반면 참조 캡처는 원본 변수를 직접 가리키는 포인터처럼 작동해요.
선생님: 원본 변경이 람다에 즉시 반영되지만, 변수 수명이 끝나면 위험해질 수 있어요.
선생님: 그래서 바로 쓰고 버릴 람다엔 참조 캡처, 오래 보관할 람다엔 값 캡처를 권장해요.