람다 표현식(lambda expression)
C++11 이상에서 지원하는 기능으로, 람다 표현식(또는 람다 함수, 람다)은 함수에 인수로 호출되거나 전달되는 위치에서 익명 함수 개체(클로저, closure)를 정의할 수 있는 기능이다.
- 캡처(capture): 람다가 선언된 스코프에 있는 변수를 참조(&) 또는 값(=)으로 복사하여 사용할지의 여부를 정한다. 디폴트를 사용하는 경우([=] 또는 [&]) 람다 본문에 선언되어있는 외부 변수만 캡처된다. 필요에 따라서 람다 외부의 변수명을 명시하여 해당 변수에 대해서만 참조나 값으로 캡처하는 방식을 지정할 수 있다. 람다 외부의 로컬 변수를 참조로 캡처하는 경우, 클로저의 수명이 로컬 변수의 수명보다 오래 지속될 수 있어 액세스 위반(댕글링, dangling)이 될 수 있으므로 사용에 주의해야 한다(따라서 이런 경우에는 값으로 캡처해야 한다, 아래의 클로저 항목 및 예시 코드 참고, 중요★).
- (optional) 매개 변수 목록
- (optional) mutable-specification: 일반적인 람다의 함수 호출 연산자는 const-by-value이지만 mutable을 사용하면 이를 취소한다. 즉, mutable 키워드를 사용해서 람다 본문에서 값으로 캡처되는 람다 외부 변수의 값을 수정할 수 있다.
- (optional) exception-specification: noexcept 키워드를 사용하여 예외를 throw하지 않을 수 있다.
- (optional) 후행 반환 형식(trailing return type): 기본적으로 람다의 반환 형식은 자동으로 추론되지만, 강제적으로 반환형을 지정하거나 auto로 지정할 수 있다.
- 람다 본문
클로저(closure)
람다 표현식에 의해 생성되는 런타임 상에서 존재하게 되는 익명 함수 오브젝트이다. 클로저 오브젝트는 임시 객체로서 실행되고 난 다음 명령줄의 끝에서 파괴된다.
* Effective Modern C++의 저자 Scott Meyers에 의하면, 람다와 클로저의 관계는 클래스와 클래스 인스턴스의 차이와 같다고 한다.
람다 표현식을 이용해 어떤 로컬 변수의 레퍼런스를 캡처하여 어떠한 컨테이너(std::vector<> 등)에 데이터를 저장하는 경우와 같이, 람다 표현식의 클로저가 참조로 캡처하는 로컬 변수보다 수명이 길어지는 경우에는 액세스 위반(댕글링, dangling)이 일어날 수 있다(아래 예시 참고).
#include <functional>
#include <vector>
std::vector<std::function<int(int)>> functions;
void MyFunc()
{
// 참조로 캡처될 로컬 변수
int a = 10;
functions.emplace_back
(
// 컨테이너에 클로저를 보관
[&](int num) { return num + a; }
);
}
// MyFunc 함수의 외부에서 functions를 통해 클로저가 동작하는 경우, 액세스 위반
* 해당 카테고리의 글은 Microsoft 공식 홈페이지의 기술 문서 페이지와 Stephan Prata의 저서 C++ 기초 플러스 (6판, 번역본) 서적 및 기타 구글링을 통한 정보 수집 등을 토대로 개인적으로 요약/정리해 본 글입니다. 만약 잘못 정리된 내용이 있다면, 댓글이나 이메일로 공유해주시면 수정하도록 하겠습니다.
'프로그래밍 공부 > C++ 프로그래밍' 카테고리의 다른 글
[C++ 기초] STL priority_queue 템플릿 클래스 (0) | 2023.05.30 |
---|---|
[C++ 기초] 부동소수점 표기법(Floating-Point Arithmetic) (0) | 2023.05.23 |
[C++ 기초] 표준 입출력 스트림(Stream)의 동기화 및 입출력 속도의 최적화 (0) | 2023.05.13 |
[C++ 기초] 반복문(Loop Statement)과 스택 프레임(Stack Frame), 배열 형식과 STL 컨테이너 (0) | 2023.05.10 |
댓글