2 분 소요

Lambda?

‘이름 없는 함수’에 대한 일종의 표현식으로
‘익명 타입의 객체’(Closure)로 만들어지며
해당 객체가 operator()를 통해 함수처럼 호출

  • C++ 11 부터 도입
  • ‘즉석’에서 만들어 사용하는 함수
    (위에서 말하였듯, 정확히는 런타임 중 생성되는 객체)

  • 람다의 ‘타입’은 이름 없는 클래스 타입! (Closure)

  • 람다 표현식의 결과는 prvalue
    • prvalue?
      Pure rvalue 로서
      rvalue 중 ‘순수한 값’에 가까움
      (리터럴 , x + y 같은 연산 결과, T{} 같은 임시객체 생성)

람다의 특징

  • 각 람다마다 ‘Closure’ 타입이 생성
    • 캡쳐의 여부에 따라 생성/대입 규칙이 달라질 수 있음
  • 호출 동작은 operator()를 통해
    • 람다 호출 시, Closure object의 operator() 가 실행
      • 값 캡쳐(copy)시엔 ‘캡처’된 복사본에 접근
      • 참조 캡쳐(ref)시엔 ‘원본’에 접근
  • 캡처 없는 람다는 ‘함수 포인터’로 변환 가능함

  • ‘댕글링’ 참조에 유의할 것
    • [&] 캡쳐로 가져온 대상이 메모리 해제가 되어 있을 경우
      ‘정의되지 않은 동작’이 발생 가능함
      • this로 캡쳐한 경우도 ‘수명’에 주의할 것

람다의 사용법

  • 기본 문법
[capture](params) -> return_type { body }
  • capture : 바깥 변수를 가져오는 방식
  • params : 함수 파라미터
  • return_type : 생략하면 자동 추론
  • body : 실행할 코드

캡쳐

  • 외부 변수를 어떻게 가져올지를 결정하는 방식
캡처 의미
[] 캡처 없음
[=] 사용한 변수 전부 캡처
[&] 사용한 변수 전부 참조 캡처
[x] x만 값 캡처
[&x] x만 참조 캡처
[x, &y] 혼합
[this] 클래스 내부 멤버 접근
  • mutable 키워드
    ‘값 캡쳐’를 수정할 수 있도록 하는 키워드
int x = 5;

auto f = [x]() mutable {
    x += 10;     // 내부 복사본 변경
    return x;
};

int r = f(); // 15
// 바깥 x는 여전히 5
  • init-capture
    캡쳐 하면서 이름/값을 새로 지정
    std::move를 사용한 ‘이동’도 가능함!
int base = 10;

auto f = [v = base * 2](int x) {
    return v + x;  // v는 20으로 저장됨
};

---

#include <memory>
auto p = std::make_unique<int>(7);

auto g = [q = std::move(p)]() {
    return *q;
};

std::function

  • 람다를 ‘함수 포인터’ 처럼 저장하거나, 다른 함수의 인자로 넘길때 사용
    • 보통 auto를 사용하는 편도 많음(단순 호출/전달 에 용이)
    • 특정 ‘콜백’용 함수로 저장 / 교체 하는 경우, 표준으로 사용 가능
      • 공통 래핑용 인터페이스이기에, ‘간접 호출’ 오버헤드 + 캡쳐가 클 경우, 힙 할당 등의
        성능 이슈 발생 가능
#include <functional>

std::function<int(int, int)> func = [](int a, int b) { return a + b; };

람다의 사용 이유

  • 가독성 + 편리함
    별도의 함수를 만들지 않고 ‘관련 로직’ 근처의 인스턴스 함수를 만들어
    의도를 이해하기 쉬운 편
    • 특히 sort, find 같은 stl 알고리즘과 궁합이 좋은 편
#include <algorithm>
#include <vector>

std::vector<int> v{5, 1, 4, 2, 3};

std::sort(v.begin(), v.end(), [](int a, int b) {
    return a < b;
});

int t = 3;
auto it = std::find_if(v.begin(), v.end(), [t](int x) {
    return x >= t;
});

참고 사이트

댓글남기기