控制 lambda 的生命周期

Controlling the lifetime of a lambda

我有一段代码调用了 async rdma-write。 rdma API 收到 void* context 我想用它来传递操作完成时要调用的回调。

void invoke_async_operation(... some stuff to capture ...) {
  ...
  MyCallBackType* my_callback = // Create callback somehow
  rdma_post_write(..., my_callback);
  ...
}

void on_complete(void* context) {
  (*(MyCallbackType*)context)();
}

我认为最好在此处使用 lambda,因为它可以轻松捕获稍后回调调用所需的所有上下文。但是我在 What is the lifetime of a C++ lambda expression? 中看到 lambda 生命周期仅限于定义它的范围。

请注意,我无法复制 lambda,因为上下文是一个指针。

这里正确的做法是什么?我应该坚持使用 lambda 并以某种方式延长它们的寿命,还是有更好的方法?谢谢

lambda 的生命周期

表示 lamda 表达式并允许调用它的对象确实遵守通常的范围规则。

但是可以复制此对象(例如,将其作为参数传递给函数或构造函数,或将其分配给全局变量,或您想要执行的任何其他操作),以便可以在以后的任何时候调用 lambda ,即使在它最初定义的范围被保留之后。

正是由于 lambda 的这种潜在的长期生存,您可以找到很多问题、博客或书籍来建议谨慎使用 lambda 捕获,尤其是通过引用捕获时,因为 lambda 本身(而不是它的匿名代理对象)即使在被引用的对象被销毁后也可以被调用。

你的回拨问题

您在设计中受到了使用 OS 回调的限制,该回调只能传达在设置回调时传递给它的原始指针。

解决这个问题的方法可能是使用 std::function object of the standard <functional> 库。这里有一个小函数向您展示它是如何工作的:

function<void()>* preparatory_work() {
    auto l = [](){ cout<< "My lambda is fine !" <<endl; } ;  // lambda 
    function<void ()> f = l;                                 // functor
    auto p = new function<void()>(l);                        // a functor on the heap
    
    l();  // inovke the lambda object 
    f();  // invoke the functor 
    (*p)(); // invoike functor via a pointer 

    return p; 
}

函数对象与任何其他对象一样易于使用,并且与函数指针一样易于声明。然而,它们比函数指针强大得多,因为它们基本上可以引用任何可调用对象。

如你所见,在上面的例子中,我用new分配了一个函数objet,并返回了它的指针。所以你确实可以稍后调用这个函数:

int main() {
    auto fcp = preparatory_work();  // fcp is a pointer 
    (*fcp)();
                                    // and even with casting as you would like
    void *x = (void*)fcp; 
    (*(function<void()>*)x)();   // YES !!! 
} 

这里是online demo