lambdas及其捕获的值

时间:2013-04-06 17:03:50

标签: c++ visual-studio-2010 c++11 lambda frp

我最近刚刚进行了一些功能性反应式编程的实验以及它是什么,当我尝试在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,并将它的impor设置为一个像这样的&amp; {meh.m_Data + peh.m_Data}的lambda。然后将Reactive分配给cheh。当值m_meh添加了4,并且cheh被更新时,它的影响因子被调用了新值14,这就是打印到屏幕上的内容,正如我想要的那样。

然后我开始思考,如果其中一个参与了cheh的情感的Reactives超出了范围。如果处理不当,程序应该出错。 所以我这样做了,

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

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

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

在调用更新时,发生在他的情感中的Reactive peh超出了范围并且不再存在。然而,这个程序和cheh的情感成功执行,它打印出14就像以前一样。我知道lambda中的值是通过引用捕获传入的,那么affecter函数如何仍然可以访问peh的引用?只要lambda存在,对象或整数类型是否通过引用传递给lambda会强制它们持久存在?闻起来有点腥味......

1 个答案:

答案 0 :(得分:3)

  

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

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

但是,未定义的行为并不一定意味着会发生崩溃。有可能(在这里似乎就是这种情况)程序只是似乎才能正常工作。这可能不适用于其他计算机,或重新启动计算机后。

另见this brilliant explanation为什么即使在超出范围之后也可以访问对象的原因。