람다와 함수 객체: 콜백·정렬 조건·필터를 읽기 좋게 만들기
17강. 람다와 함수 객체: 콜백·정렬 조건·필터를 읽기 좋게 만들기
이번 강의에서 해결할 문제
람다는 짧은 조건을 가까이에 둘 수 있지만 [&]로 모든 지역 변수를 참조 캡처한 뒤 콜백을 장기 저장하면 지역 수명이 끝난 뒤 댕글링이 됩니다. 편리한 문법보다 캡처 대상과 실행 시점을 먼저 분석해야 합니다.
학습 목표
먼저 알아야 할 핵심 개념
람다는 이름 없는 함수 객체를 만드는 문법입니다. []는 캡처 없음, [limit]는 값 복사, [&limit]는 참조 관찰입니다. 함수 본문은 호출될 때 실행되므로 콜백이 스코프 밖에서 실행되면 참조 캡처 대상이 살아 있어야 합니다. std::function은 다양한 호출 대상을 저장하지만 타입 소거와 할당 비용이 있을 수 있습니다.
왜 이 문제가 위험한가
지역 변수 참조를 캡처한 콜백을 반환하거나 비동기 큐에 넣으면 호출 시점에 대상이 사라질 수 있습니다. this를 캡처한 콜백도 객체 파괴 뒤 실행되면 위험합니다. [=], [&] 기본 캡처는 실제 의존성을 숨겨 리뷰하기 어렵습니다.
가장 작은 예제로 시작하기
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
struct Task { std::string name; int priority{}; };
int main() {
const std::vector<Task> tasks{{"test", 1}, {"build", 3}, {"docs", 2}};
const int minimum{2};
const auto highPriority = [minimum](const Task& task) {
return task.priority >= minimum;
};
const auto count = std::count_if(tasks.begin(), tasks.end(), highPriority);
std::cout << count << '\n';
}
코드 한 줄씩 이해하기
minimum은 값 캡처되어 람다 객체 안에 독립적으로 저장됩니다.Task는 읽기만 하므로 const 참조 인자입니다.- 람다를
highPriority라는 이름에 담아 조건 의도를 드러냅니다. count_if는 조건이 true인 원소 수를 계산합니다.- 이 람다는 호출 스코프 안에서 사용되지만 값 캡처라 더 오래 저장해도
minimum수명에는 의존하지 않습니다.
실행 결과와 메모리·동작 흐름
우선순위 3과 2인 두 작업이 조건을 만족해 2가 출력됩니다. minimum을 3으로 바꾸면 출력은 1입니다. 람다 객체는 캡처 당시의 정수 값을 보관합니다.
단계별 실습
흔한 실수와 해결 방법
언제 사용하고 언제 피할까
짧고 지역적인 정렬·필터 조건, 즉시 호출되는 알고리즘 콜백에 람다가 적합합니다. 장기 저장, 비동기 실행, 복잡한 상태를 가진 정책은 명시적 타입과 수명 계약을 고려합니다.
게임 개발 연결
Unreal Delegate에 람다나 객체 함수를 바인딩할 때도 실행 시점과 대상 수명이 핵심입니다. 캡처한 UObject raw 주소가 GC 뒤 남지 않도록 엔진이 제공하는 약한 바인딩·등록 해제 규칙을 확인하며, 표준 std::function과 Delegate의 수명 추적이 같다고 가정하지 않습니다.
이해 점검 질문 3개
- 값 캡처와 참조 캡처가 콜백 저장 기간에서 어떻게 다른가요?
[&]기본 캡처가 코드 리뷰를 어렵게 만드는 이유는 무엇인가요?- this를 캡처한 콜백이 객체 파괴 뒤 실행되지 않게 하는 방법은 무엇인가요?
핵심 요약
다음 강의 연결
18강. optional·variant·any에서 값 없음과 여러 가능한 상태를 포인터나 임의 정수 대신 타입으로 표현합니다.
람다와 함수 객체: 콜백·정렬 조건·필터를 읽기 좋게 만들기 미니 퀴즈
선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.
학습을 마쳤나요?
직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.