我有一段调用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,因为context是指针。
这里的正确方法是什么?我应该坚持使用lambdas并以某种方式延长他们的寿命,还是有更好的方法?感谢。
答案 0 :(得分:2)
表示lamda表达式并允许调用它的对象,实际上遵循通常的范围规则。
然而,可以复制此对象(例如,将其作为参数传递给函数或构造函数,或将其分配给全局或其他任何您想要执行的操作),以便可以在以后任何时候调用lambda,甚至在最初定义的范围之后是剩下的。
由于lambda的这种潜在的长期生存,你可以找到很多问题,博客或书籍,建议仔细使用lambda捕获,特别是如果通过引用捕获,因为lambda本身(而不是它的匿名)即使在引用的对象被销毁之后也可以调用代理对象。
通过使用OS回调来限制您的设计,该回调只能传达在设置回调时传递给它的原始指针。
解决这个问题的方法可能是使用标准std::function库的<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 !!!
}