0

我最近刚刚对函数式反应式编程及其是什么进行了一些试验,当我试图在 c++ 中实现类似的东西时,我求助于 lambda。我想出了这样的开始,

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;
};

到目前为止它只支持添加。我试图创建一个称为响应式的对象,它可以环绕任何其他类型,除了在对其执行数学运算时,会创建一个 lambda,在该操作发生的位置,以便记住已经完成的操作之前,并在其中一个影响值发生更改时再次执行此操作(在调用更新函数之后)。例如,如果我要这样做。

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

那么继承人会发生什么。将第五行中的两个 Reactive 相加将使另一个 Reactive 将它们的两个值添加到 10,并将其影响器设置为执行类似操作的 lambda, &{meh.m_Data + peh.m_Data} 。然后那个 Reactive 将被分配给 cheh。当值 m_meh 添加了 4 并更新了 cheh 时,它的影响器被调用为新值 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();

在调用 update 时,在他的影响器中发生的反应性 peh 已经超出范围并且不再存在。然而,这个程序和 cheh 的影响器成功执行,它像以前一样打印出 14。我知道 lambda 中的值是由引用捕获传入的,那么影响函数如何仍然访问对 peh 的引用?只要 lambda 存在,通过引用传递给 lambda 的对象或整数类型是否会强制它们持续存在?有什么腥味...

4

1 回答 1

3

我知道 lambda 中的值是由引用捕获传入的,那么影响函数如何仍然访问对 peh 的引用?只要 lambda 存在,通过引用传递给 lambda 的对象或整数类型是否会强制它们持续存在?有什么腥味...

该程序具有未定义的行为。正如您所怀疑的那样,通过引用捕获不会延长这些引用所绑定的对象的生命周期,并且取消引用对不再存在的对象的引用是 UB。

但是,未定义的行为并不一定意味着会发生崩溃。有可能(就像这里的情况一样)该程序似乎工作正常。这在另一台机器上可能不是真的,或者在你重新启动你的机器之后。

另请参阅这个精彩的解释,说明为什么即使在对象超出范围后也可以访问对象。

于 2013-04-06T17:07:11.157 回答