C++ 람다(lambda)란?
C++ 11에 추가된 함수 객체 표현식으로서, 주로 다른 함수의 인자로 전달되거나 함수 내부에서 익명 함수로 사용됩니다.
람다는 C++의 클로저(Closure)로서 캡쳐를 통해 람다 함수 내부에서 외부 변수에 대한 접근이 가능합니다.
람다 함수 객체를 생성하는 방법
람다 왼쪽부터 오른쪽으로 순서대로 개시자(introducer), 인자(parameters), 반환 타임(return type), 함수의 몸통(statement)으로 구성되어 있습니다.
람다 내부에서 외부 변수에 접근할 때 접근할 변수를 인자로 전달할 수도 있지만, Captrue 기능을 이용해서 접근할 수 있습니다. 이는 람다를 핸들러로서 사용하기 위해 정해진 인터페이스 형태로 정의해야만 할 때 매우 유용하게 사용할 수 있습니다.
[&] Capture
[&] Captrue는 외부의 모든 변수를 Call-by-reference 형태로 가져올 때 사용합니다.
[=] Capture
[=] Capture는 외부의 모든 변수를 Call-by-value 형태로 가져올 때 사용합니다. 그리고 Call-by-value 형태로 Capture할 경우 자동적으로 const 속성이 붙습니다.
값 형태로 가져온 Capture 값을 수정하기 위해서는 [=]() mutable -> {} 형태로 사용해야 합니다.
[&, x, y]
[&, x, y] Capture는 외부의 x, y는 값 형태로 가져오고 나머지 모든 변수를 레퍼런스 형태로 가져오는 방식입니다. 이와같이 값과 래퍼런스를 혼합해서 Capture 할 수 있습니다.
[=] or [&] 그리고 this
멤버 함수 내부에서 람다를 생성하고 [=] or [&] 형태로 캡쳐할 경우 자동으로 this가 캡쳐 됩니다.
람다와 외부 객체 참조
#include <iostream>
using namespace std;
class CTest {
public:
CTest() {
cout << "CTest\n";
}
~CTest() {
cout << "~CTest\n";
}
CTest(const CTest& obj) {
cout << "Copy Creator\n";
}
void SayHello() const {
cout << "Hello World\n";
}
};
auto GetLambda() {
CTest test;
// [=]으로 캡쳐해야 함
return [&]() -> void {
test.SayHello();
};
}
int main() {
auto g = GetLambda();
g();
return 0;
}
GetLambda 함수를 호출하면 내부에서 생성된 람다 객체가 return 되면서 test 객체의 소멸자가 호출됩니다. 그렇기 때문에 람다 객체가 외부 변수에 접근할 때 해당 변수가 스택에서 이미 제거 될 수 있다는 점을 생각하고 사용해야 합니다. 즉, GetLambda 안에서 생성된 람다 객체는 GetLambda 함수 스택보다 오랫동안 유지되기 때문에 test를 Call-by-value 형태로 캡쳐해야 합니다.