ProgramingTip

C ++ 람다 식의 수명은 얼마입니까?

bestdevel 2020. 11. 18. 09:31
반응형

C ++ 람다 식의 수명은 얼마입니까?


( C ++에서 람다 파생 암시 적 펑터의 수명은 무엇입니까?를 이미 읽었 으며 질문에 대한 답변은 없습니다.)

C ++ 람다 구문은 호출 연산자와 일부 상태를 사용하여 익명 클래스의 인스턴스를 만들기위한 설탕 일 뿐이라는 것을 이해하고 해당 상태의 수명 요구 사항을 이해합니다 (참조로 방송 여부에 따라 결정됨). 람다 자체의 수명? 다음 예에서 std::function반환 인스턴스가 유용할까요?

std::function<int(int)> meta_add(int x) {
    auto add = [x](int y) { return x + y; };
    return add;
}

그렇다면 어떻게 작동 합니까? 이 나에게 너무 많은 마술처럼. std::function내가 가지고있는 것에 따라 매우 무거울 수있는 전체 인스턴스 복사하는 것만으로 작동하는 것을 상상할 수 있습니다. 과거에는 std::function기본적으로 함수 포인터를 사용합니다. 빨리. std::function의 유형 삭제 문제가있는 것 입니다.


수명은 람다를 손으로 굴린 펑터로 교체 한 경우와 정확히 일치합니다.

struct lambda {
   lambda(int x) : x(x) { }
   int operator ()(int y) { return x + y; }

private:
   int x;
};

std::function<int(int)> meta_add(int x) {
   lambda add(x);
   return add;
}

객체는 meta_add함수에 로컬로 생성 된 다음 [값을 포함하여 x]를 반환 값으로 이동 한 다음 로컬 인스턴스가 범위를 벗어나서 삭제됩니다. 그러나 함수에서 반환 된 std::function객체는이를 보유한 객체가 수행하는 한 유효합니다 . 얼마나 오래 존재하는 호출이 호출되는지.


std::function람다보다 더 혼란스러워 .

std::function유형 삭제라는 기술을 사용합니다. 여기에 빠른 비행이 있습니다.

class Base
{
  virtual ~Base() {}
  virtual int call( float ) =0;
};

template< typename T>
class Eraser : public Base
{
public:
   Eraser( T t ) : m_t(t) { }
   virtual int call( float f ) override { return m_t(f); }
private:
   T m_t;
};

class Erased
{
public:
   template<typename T>
   Erased( T t ) : m_erased( new Eraser<T>(t) ) { }

   int do_call( float f )
   {
      return m_erased->call( f );
   }
private:
   Base* m_erased;
};

유형을 지우려는 이유는 무엇입니까? 우리가 원하는 유형이 int (*)(float)아닙니까?

유형 삭제가 허용하는 것은 Erased이제와 같이 호출 가능한 모든 값을 수있는 것 int(float)입니다.

int boring( float f);
short interesting( double d );
struct Powerful
{
   int operator() ( float );
};

Erased e_boring( &boring );
Erased e_interesting( &interesting );
Erased e_powerful( Powerful() );
Erased e_useful( []( float f ) { return 42; } );

이 :

[x](int y) { return x + y; };

다음과 동일 : (또는 고려할 수 있음)

struct MyLambda
{
    MyLambda(int x): x(x) {}
    int operator()(int y) const { return x + y; }
private:
    int x;
};

그래서 당신의 개체는 그와 같은 개체를 반환합니다. 잘 정의 된 복사 생성자가 있습니다. 따라서 함수에서 올바르게 복사 할 수 있다는 것이 매우 합리적입니다.


게시 한 코드에서 :

std::function<int(int)> meta_add(int x) {
    auto add = [x](int y) { return x + y; };
    return add;
}

std::function<int(int)>함수에 의해 리턴되는 오브젝트가 실제로 로컬 변수에 할당 된 람다 함수 객체의 이동 된 인스턴스를 보유하고있다 add.

값 또는 참조로 캡처하는 C ++ 11 람다를 정의하면 C ++ 컴파일러는 람다가 호출되거나 변수에 할당 될 때 생성되는 인스턴스 인 고유 함수 형식을 자동으로 생성합니다. 설명을 위해 C ++ 컴파일러는에 의해 정의 된 람다에 대해 다음 클래스 유형을 생성 할 수 있습니다 [x](int y) { return x + y; }.

class __lambda_373s27a
{
    int x;

public:
    __lambda_373s27a(int x_)
        : x(x_)
    {
    }

    int operator()(int y) const {
        return x + y;
    }
};

그러면 meta_add함수는 본질적으로 다음과 같습니다.

std::function<int(int)> meta_add(int x) {
    __lambda_373s27a add = __lambda_373s27a(x);
    return add;
}

편집 : 그건 그렇고, 당신이 이것을 알고 있는지 확실하지 않지만 이것은 C ++ 11에서 함수 커링 의 예입니다 .

참고 URL : https://stackoverflow.com/questions/7941562/what-is-the-lifetime-of-ac-lambda-expression

반응형