728x90

함수 객체는 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 포인터를 복사하기 위함인지 한눈에 파악하기 어렵습니다.

 

이런 이유로 캡쳐 방식을 지정할 때는 변수별로 별도로 지정하는 것이 코드 가독성을 높이고 이는 곧 디버깅을 쉽게 합니다.

728x90

'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

+ Recent posts