[람다]
C++에서 함수를 선언할 때는 보통 선언과 구현을 실시한다. 하지만 람다를 사용할 경우 선언과 동시에 바로 함수처럼 활용할 수 있다.
[캡처](매개변수){함수바디}(호출인자) // 형태
[](int _a, int _b){return a + b}; // 함수를 만들기만 한 것
[](int _a, int _b){return a + b}(10, 20); // 이건 함수를 만들고 바로 쓴 것
캡처를 선언하고, 매개 변수를 설정한 뒤 구현부를 등록해주고 필요 시 매개변수를 넣어주면 된다. 매개 변수와 호출인자는 사용하지 않으면 보통 생략할 수 있다.
[사용처]
여러 곳에서 무궁무진하게 활용 가능하겠지만, 작성자의 경우에는 Inline으로 처리될 수 있을 정도의 짧은 함수이면서 굳이 재활용하지 않는 함수일 경우 사용하곤 한다. 일반적인 sort의 경우 오름차순 정렬이 실시되지만, 특정 로직을 추가 실행하거나 할 경우에는 함수 포인터로 원하는 로직이 작성된 함수를 전달해주면 된다. 이때 람다를 사용할 수 있다.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
vector<int> Arr = { 8, 4, 10, 2, 7, 9, 1};
sort(Arr.begin(), Arr.end(), [](int _Left, int _Right) { return _Left > _Right; });
for (int Value : Arr) cout << Value << endl;
return 0;
}
[람다 캡쳐]
람다 사용의 주의점은 해당 구현부가 현재의 스택에서 분리된다는 점이다. 예를들어, 아래와 같이 람다를 선언하면 람다의 함수 바디는 main 함수의 스택 영역과 분리된 영역으로 존재하게 된다.
int main()
{
int Value = 0;
[](int _value)
{
int Value = 0;
};
}
하지만 이를 위해 람다 캡처를 지원해주는데, 람다 캡처에 특정 연산자를 활용하면 스택에 존재하는 값을 활용할 수 있게 된다. 캡처의 종류는 네 가지가 있다.
- =
- &
- 단일캡처
- this
1. =캡처
해당 캡처는 모든 외부 변수를 복사해서 람다 함수 내부에서 사용한다는 뜻이 된다.
int main()
{
int a = 10;
int* IntPtr = &a;
std::cout << "IntPtr : " << IntPtr << std::endl;
std::function<void()> Ptr = [=]()
{
int* RamPtr = nullptr;
RamPtr = IntPtr;
std::cout << "IntPtr : " << IntPtr << std::endl;
std::cout << "RamPtr : " << RamPtr << std::endl;
};
Ptr();
}

하지만 해당 캡처 방식은 단순하게 외부에 존재하는 변수에 대한 대입이 이뤄지지 않고 에러가 발생하는데, 아래의 테스트를 해보면 이유를 확인해볼 수 있다.
// 람다 구현부에서 외부 변수 int a;에 대해 a = 20; 수행이 안되는 이유
int main()
{
int a = 20;
__int64 aAddRess = (__int64)&a;
std::cout << "a : " << a << std::endl;
std::cout << "aAddRess : " << aAddRess << std::endl;
std::function<void()> Ptr = [=]()
{
__int64 aAddRess = (__int64)&a;
std::cout << "a : " << a << std::endl;
std::cout << "aAddRess : " << aAddRess << std::endl;
};
Ptr();
}

메모리의 주소가 차이난다는 것을 확인할 수 있는데, 이것은 [=캡처]가 단순히 호출한 영역의 메모리를 복사해서 들고있기 때문에 발생하는 것이다.
2. &캡처
위 현상을 해결하기 위해 [&캡처]가 있다. 이전과 동일하게 테스트해보면 외부 변수와 람다 구현부 변수의 주소값이 동일한 것을 확인할 수 있다.
int main()
{
int a = 20;
__int64 aAddRess = (__int64)&a;
std::cout << "a : " << a << std::endl;
std::cout << "aAddRess : " << aAddRess << std::endl;
std::function<void()> Ptr = [&]()
{
int Test = 100;
a = Test;
__int64 aAddRess = (__int64)&a;
std::cout << "a : " << a << std::endl;
std::cout << "aAddRess : " << aAddRess << std::endl;
};
Ptr();
}

해당 캡처 방식은 호출한 영역의 메모리를 참조해서 활용하는 방식이다. 물론 이 방식은 스택 영역에서 활용할 경우 외부 변수가 파괴될 염려가 있어 사용에 주의해야 한다.
3. 단일캡처
영역의 메모리 전체를 복사하는 방식이 아니라, 단일 변수에 대해서도 복사가 가능하다.
int main()
{
int a = 20;
int b = 30;
__int64 aAddRess = (__int64)&a;
__int64 bAddRess = (__int64)&b;
std::cout << "a : " << a << std::endl;
std::cout << "b : " << b << std::endl;
std::cout << "aAddRess : " << aAddRess << std::endl;
std::cout << "bAddRess : " << bAddRess << std::endl;
std::function<void()> Ptr = [&a, b]()
{
int Test = 100;
a = Test;
Test = b;
__int64 aAddRess = (__int64)&a;
__int64 bAddRess = (__int64)&b;
std::cout << "a : " << a << std::endl;
std::cout << "b : " << b << std::endl;
std::cout << "aAddRess : " << aAddRess << std::endl;
std::cout << "bAddRess : " << bAddRess << std::endl;
};
Ptr();
}

4. this캡처
물론 클래스 멤버변수까지 캡처하는 방식도 가능하다. 이때는 호출하는 대상의 this를 캡처에 전달하면 된다. [&캡처]와 유사한 방식으로 동작한다.
class Test
{
public:
void Call()
{
__int64 aAddRess = (__int64)&a;
__int64 bAddRess = (__int64)&b;
std::cout << "a : " << a << std::endl;
std::cout << "b : " << b << std::endl;
std::cout << "aAddRess : " << aAddRess << std::endl;
std::cout << "bAddRess : " << bAddRess << std::endl;
std::function<void()> ClassFunction = [this]()
{
int Test = 100;
a = Test;
Test = b;
__int64 aAddRess = (__int64)&a;
__int64 bAddRess = (__int64)&b;
std::cout << "a : " << a << std::endl;
std::cout << "b : " << b << std::endl;
std::cout << "aAddRess : " << aAddRess << std::endl;
std::cout << "bAddRess : " << bAddRess << std::endl;
};
ClassFunction();
}
int a = 0;
int b = 0;
__int64 aAddRess = 0;
__int64 bAddRess = 0;
};
int main()
{
Test Obj = Test();
std::function<void()> Function = std::bind(&Test::Call, Obj);
Function();
}

'C++' 카테고리의 다른 글
| [C++] 클래스 template (0) | 2025.05.13 |
|---|---|
| [C++] 함수 template (0) | 2025.05.13 |
| [C++] 캐스팅(Casting) (0) | 2025.05.13 |
| [C++] std::enable_shared_from_this와 shared_from_this() (0) | 2025.05.13 |
| [C++] 스마트 포인터 (0) | 2025.03.21 |