2013-04-06 4 views
0

저는 기능적 반응 형 프로그래밍을 사용하여 최근에 실험을 해오 고 있으며, C++과 같은 것을 구현하려고 할 때 람다에게 도움을 청했습니다. 이런 식의 시작을 생각해 냈습니다.lambdas와 그 값을 캡쳐했습니다.

template<class T> 
class Reactive 
{ 
public: 
    Reactive(T data) 
    { 
     m_Data = data; 
    } 

    Reactive(std::function<T()> func, T data) 
    { 
    m_Data = data; 
    m_Affecter = func; 
    } 

    template<class H> 
    Reactive & operator+(const H & rhs) 
    { 
     m_Data += rhs; 

     return *this; 
    } 

    template<class H> 
    Reactive operator+(Reactive<H> & rhs) 
    { 
    std::function<decltype(m_Data + rhs.m_Data)()> func; 

    if (!rhs.m_Affecter) 
     func = [&](){return m_Data + rhs.m_Data;}; 
    else 
     func = [&](){return m_Data + rhs.m_Affecter();}; 

    return Reactive<decltype(m_Data + rhs.m_Data)> (func, m_Data + rhs.m_Data); 
    } 

    Reactive & operator=(const T & data) 
    { 
     m_Data = data; 

     return *this; 
    } 

    Reactive & operator=(const Reactive & rhs) 
    { 
     m_Data = rhs.m_Data; 
     m_Affecter = rhs.m_Affecter; 

     return *this; 
    } 

    T & Get() 
    { 
     return m_Data; 
    } 

    void Update() 
    { 
     m_Data = m_Affecter(); 
    } 

private: 
    std::function<T()> m_Affecter; 
    T m_Data; 
}; 

지금까지 추가 기능 만 지원합니다. 나는 수학 연산이 수행 될 때, 람다가 생성 될 때, 그 연산이 일어나는 곳을 제외하고, 어떤 다른 타입을 감쌀 수있는 반응식이라는 객체를 만들기 위해 노력했다. 업데이트 기능을 호출 한 후 변경 사항 중 하나가 값에 영향을 줄 때 다시 시도 할 수 있습니다. 예를 들면 내가 이것을 할 수 있다면.

Reactive<int> cheh = 0; 
Reactive<int> meh = 3; 
Reactive<int> peh = 7; 
cheh = meh + peh; 
meh = meh + 4; 
cheh.Update(); 
std::cout << cheh.Get(); 

그러면 무엇이 일어날 지 알 수 있습니다. 5 개의 Reactives를 합하면 두 개의 값을 가진 Reactive가 10에 추가되고, 이와 비슷한 것을하는 람다에게 affector가 설정됩니다. & {meh.m_Data + peh.m_Data}. 그런 다음 Reactive가 cheh에게 할당됩니다. m_meh 값이 4로 추가되고 cheh가 업데이트되면 affofector가 14라는 새 값으로 호출되었으며 이것이 의도 한 그대로 화면에 인쇄됩니다.

하지만 저는 생각하기에, Cheh의 감기에 참여하는 반응성 물질 중 하나가 범위를 벗어나면 어떻게 될까요? 제대로 처리되지 않으면 프로그램에서 오류가 발생합니다. 그래서 내가 이런 짓을, 업데이트가 호출되는 시점에서

Reactive<int> cheh = 0; 
Reactive<int> meh = 3; 

{ 
    Reactive<int> peh = 7; 
    cheh = meh + peh; 
    peh = peh + 4; 
} 

cheh.Update(); 
std::cout << cheh.Get(); 

, 그의 affecter에서 일어난 반응성 PEH는 범위를 벗어난 없어 더 이상 존재했다. 그러나이 프로그램과 Cheh의 영향 도구는 성공적으로 실행되며 이전과 마찬가지로 14 개의 내용이 인쇄됩니다. 나는 람다의 값이 참조 캡처에 의해 전달되었다는 것을 알고 있습니다. 그래서 감정사 함수가 어떻게 peh에 대한 참조에 여전히 액세스 할 수 있습니까? 참조에 의해 람다에 전달 된 객체 또는 통합 유형은 람다가 존재하는 한 계속 유지하도록 강제합니까? 뭔가 냄새가 나는 냄새가 난다.

답변

3

나는 람다의 값이 참조 캡처에 의해 전달되었으므로 감기 기능이 어떻게 peh에 대한 참조에 계속 액세스 할 수 있는가? 참조에 의해 람다에 전달 된 객체 또는 통합 유형은 람다가 존재하는 한 계속 유지하도록 강제합니까? 뭔가 냄새가 나는데 ...

프로그램에 정의되지 않은 동작이 있습니다. 참조로 캡처하면 이 아닌은 해당 참조가 바인딩 된 객체의 수명을 연장하고 더 이상 존재하지 않는 객체에 대한 참조를 참조 해제하는 것은 UB입니다.

그러나 정의되지 않은 동작은 반드시 충돌이 발생할 것이라는 의미는 아닙니다. 프로그램이 단지 일 것입니다 (아마도 여기에있는 것처럼 보입니다). 잘 작동하려면으로 보입니다. 다른 컴퓨터에서 또는 컴퓨터를 다시 부팅 한 후에는이 내용이 적용되지 않을 수 있습니다.

범위를 벗어난 후에도 개체에 액세스 할 수있는 것처럼 보일 수있는 이유는 this brilliant explanation을 참조하십시오.

+0

실제로는 좋지 않지만 실제로는 좋은 소식입니다. 람다가 강제로 일을 계속한다면, 디버그하는 것이 끔찍한 것처럼 들리네. 나는 애국자에 참여하는 다른 반응 물질이 파괴 될 때 Reactives에 알려주는 시그널 슬롯 시스템을 설치할 것입니다. Thankee 친절하게! – FatalCatharsis

+0

@FatalCatharsis : 다행스럽게도 :) –