C++中能否引用捕获右值?嵌套lambda场景的实现问询
问题解答
1. 捕获方式的选择:值捕获 vs 引用捕获
首先明确一个关键知识点:所有命名的引用(包括右值引用)都是左值。外层lambda里的CustomFunc&& func是一个命名的右值引用变量,本身属于左值范畴。
- 若使用
&func引用捕获:你捕获的是外层lambda参数的引用,但外层lambda执行完毕后,func的生命周期随即结束。如果内层lambda会被myObj->functionBThatTakesInALambda延迟执行(比如作为异步任务、回调函数被存储后后续调用),那么调用func(input)时会访问已销毁的对象,触发未定义行为。只有当内层lambda在外层lambda执行期间同步执行时,引用捕获才安全,但这种场景非常有限,不适合作为通用写法。 - 按值捕获
[func]:会把外层的func(std::function对象)复制一份到内层lambda中,内层lambda持有独立的副本,生命周期与自身一致,无论内层lambda是同步还是异步执行都能保证安全。这是最稳妥的基础写法。
2. 更优实现方式:利用移动语义避免复制开销
因为外层的func是右值引用,我们可以借助移动语义跳过std::function的复制操作,直接转移资源到内层lambda,减少性能开销。具体有两种写法:
方式一:C++14及以上的初始化捕获
myObj->functionBThatTakesInALambda([func = std::move(func)](std::string input) { func(input); });
通过std::move(func)将外层的右值引用变量(左值)转换为右值,触发std::function的移动构造,避免复制开销,效率更高。
方式二:C++20及以上的简化写法
如果编译器支持C++20,也可以用更简洁的方式完成移动捕获,效果与上述一致:
myObj->functionBThatTakesInALambda([func = std::forward<CustomFunc>(func)](std::string input) { func(input); });
另外需要纠正你代码中的一个错误:内层lambda的参数必须显式指定类型,不能直接写(input),正确写法是(std::string input)或者(auto input)(C++14及以上支持自动类型推导)。
内容的提问来源于stack exchange,提问作者user1008636
相关产品推荐
相关产品推荐

