함수 객체는 STL에 유용하게 사용된다.
C++11에서는 이런 함수 객체를 손쉽게 작성하는 '람다' 라는 기능을 제공한다.
람다에 의해 만들어진 실행시점 객체를 클로저(closure)라고 합니다.
사용법
float ratio = 0.3;;
auto addLamda = [&ratio](int a, int b) -> float {
float ret = (a + b) / ratio;
return ret;
};
float ret = addLamda(3, 4); // 2.3333
[캡쳐](인자) -> 타입 { 구현부 }
캡쳐(capture)
함수 객체 내부에 변수를 저장하는 개념과 유사하다. '구현부'에서 외부 변수를 사용할 때 방식을 지정할 수 있다.
방식에는 복사방식, 참조방식이 있다.
예)
[=] : 모든 값을 구현부에서 복사 방식으로 사용합니다.
[&] : 모든 값을 구현부에서 참조 방식으로 사용합니다.
[a, &b] : b변수를 참조 방식으로 사용합니다. a변수는 복사 방식으로 사용합니다.
인자
함수 매개변수와 동일한 형태로 매개변수를 받습니다.
예) [](int, int)
타입
'-> bool' 과 같은 형태로 지정하지만 실제로 구현부 return 값을 통해 자동 추론 되기 때문에 생략 가능 합니다.
구현부
일반 함수 구현부와 동일하게 작성됩니다.
주의점
MS에서는 캡쳐방식에 [=], [&] 사용을 지양합니다. 이는 명시적인 캡쳐 방식을 지정하지 않을 경우에 문제를 인식하기 쉽지 않기 때문입니다.
문제가 되는 경우를 아래 코드를 통해서 살펴 봅시다.
class Knight
{
public:
auto ResetHpJob()
{
// this 포인터가 복사된 형태
// 캡터 부분만 봐서는 한눈에 알아보기 힘들다.
auto f = [=]()
{
_hp = 200;
};
//auto f = [this]()
//{
// this->_hp = 200;
//};
return f;
}
public:
int _hp = 100;
};
해당 코드는 클래스 내부에서 람다를 정의하고 있습니다. 그리고 ResetHpJob 함수에서는 멤버변수를 접근하는 람다를 반환하고 있습니다. 이 람다를 외부에서 호출하게 되면 문제가 됩니다.
왜냐하면 람다 정의부분은 객체에 의존적인 변수에 접근하고 있고 람다가 호출되는 시점에 객체가 존재한다는 보장 이 없기 때문입니다.
이런 코드 작성을 미리 방지하려면 어떻게 해야 할까요??
클래스 내부이기 때문에 멤버변수를 의심없이 접근하고 있지만 실제로는 'this->멤버변수' 와 같은 형태로 접근 되어야 합니다. 따라서 캡쳐 방식을 지정해야 합니다. 이때 [=] 와 같은 방식으로 지정하게 된다면 '='가 this 포인터를 복사하기 위함인지 한눈에 파악하기 어렵습니다.
이런 이유로 캡쳐 방식을 지정할 때는 변수별로 별도로 지정하는 것이 코드 가독성을 높이고 이는 곧 디버깅을 쉽게 합니다.
'Programming Language > C++' 카테고리의 다른 글
::/스코프 지정자 (0) | 2022.02.11 |
---|---|
std::function (0) | 2022.02.10 |
{} 중괄호 초기화 (0) | 2022.02.06 |
using - type alias declaration (0) | 2022.02.06 |
auto (0) | 2022.02.06 |