控制 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
我有一段代码调用了 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