我最近刚刚进行了一些功能性反应式编程的实验以及它是什么,当我尝试在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会强制它们持久存在?闻起来有点腥味......
答案 0 :(得分:3)
我知道lambda中的值是通过引用捕获传入的,那么affecter函数如何仍然可以访问peh的引用?只要lambda存在,对象或整数类型是否通过引用传递给lambda会强制它们持久存在?闻起来有点腥味......
该程序具有未定义的行为。正如您所怀疑的那样,通过引用捕获不延长这些引用所绑定的对象的生命周期,并且取消引用对不再存在的对象的引用是UB。
但是,未定义的行为并不一定意味着会发生崩溃。有可能(在这里似乎就是这种情况)程序只是似乎才能正常工作。这可能不适用于其他计算机,或重新启动计算机后。
另见this brilliant explanation为什么即使在超出范围之后也可以访问对象的原因。