본문 바로가기
프로그래밍 공부/C++ 프로그래밍

[C++ 기초] 람다 표현식(Lambda Expression)과 클로저(Closure)

by 섬댕이 2023. 5. 10.

 

람다 표현식(lambda expression)

C++11 이상에서 지원하는 기능으로, 람다 표현식(또는 람다 함수, 람다)은 함수에 인수로 호출되거나 전달되는 위치에서 익명 함수 개체(클로저, closure)를 정의할 수 있는 기능이다.

 

람다 구문의 구조

 

  1. 캡처(capture): 람다가 선언된 스코프에 있는 변수를 참조(&) 또는 값(=)으로 복사하여 사용할지의 여부를 정한다. 디폴트를 사용하는 경우([=] 또는 [&]) 람다 본문에 선언되어있는 외부 변수만 캡처된다. 필요에 따라서 람다 외부의 변수명을 명시하여 해당 변수에 대해서만 참조나 값으로 캡처하는 방식을 지정할 수 있다. 람다 외부의 로컬 변수를 참조로 캡처하는 경우, 클로저의 수명이 로컬 변수의 수명보다 오래 지속될 수 있어 액세스 위반(댕글링, dangling)이 될 수 있으므로 사용에 주의해야 한다(따라서 이런 경우에는 값으로 캡처해야 한다, 아래의 클로저 항목 및 예시 코드 참고, 중요★).
  2. (optional) 매개 변수 목록
  3. (optional) mutable-specification: 일반적인 람다의 함수 호출 연산자는 const-by-value이지만 mutable을 사용하면 이를 취소한다. 즉, mutable 키워드를 사용해서 람다 본문에서 값으로 캡처되는 람다 외부 변수의 값을 수정할 수 있다.
  4. (optional) exception-specification: noexcept 키워드를 사용하여 예외를 throw하지 않을 수 있다.
  5. (optional) 후행 반환 형식(trailing return type): 기본적으로 람다의 반환 형식은 자동으로 추론되지만, 강제적으로 반환형을 지정하거나 auto로 지정할 수 있다.
  6. 람다 본문

 


 

클로저(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판, 번역본) 서적 및 기타 구글링을 통한 정보 수집 등을 토대로 개인적으로 요약/정리해 본 글입니다. 만약 잘못 정리된 내용이 있다면, 댓글이나 이메일로 공유해주시면 수정하도록 하겠습니다.

댓글