You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何捕获std::unique_ptr的lambda无法传入std::packaged_task?

问题分析与解决方案

核心原因

  • 捕获std::unique_ptr的lambda是不可拷贝的:由于std::unique_ptr禁用了拷贝构造,lambda的默认拷贝构造函数会被编译器自动删除,仅保留移动构造函数。
  • C11/C14标准中,std::packaged_task要求其存储的可调用对象必须满足CopyConstructible(可拷贝构造):无论你直接传入lambda还是用std::move传入,packaged_task内部都会尝试拷贝这个可调用对象,这就是两种写法都编译失败的根本原因。
  • 从C17开始,标准放宽了std::packaged_task的要求,仅需可调用对象支持移动构造即可,这也是升级到C17后第二种写法能正常工作的原因。

解决方案

方案1:升级到C++17及以上标准

如果你的编译器支持C++17,只需在编译时启用对应标准(例如GCC/Clang添加编译选项-std=c++17),你的第二种写法即可正常编译运行:

auto uptr1 = std::make_unique<int>(1);
std::packaged_task<void()> task(std::move(
    [uptr = std::move(uptr1)]() { std::cout << *uptr << std::endl; }));

方案2:在C11/C14下包装不可拷贝的lambda

如果必须使用旧标准,可以将lambda包装在std::shared_ptr中,让packaged_task调用智能指针指向的lambda:

auto uptr1 = std::make_unique<int>(1);
// 包装lambda到shared_ptr
auto lambda_ptr = std::make_shared<decltype([uptr = std::move(uptr1)]() { std::cout << *uptr << std::endl; })>(
    [uptr = std::move(uptr1)]() { std::cout << *uptr << std::endl; });
// 构造packaged_task,通过指针调用lambda
std::packaged_task<void()> task([lambda_ptr]() { (*lambda_ptr)(); });

或者使用std::bind绑定移动后的lambda(需注意lambda的生命周期):

auto uptr1 = std::make_unique<int>(1);
auto lambda = [uptr = std::move(uptr1)]() { std::cout << *uptr << std::endl; };
std::packaged_task<void()> task(std::bind(std::move(lambda)));

内容的提问来源于stack exchange,提问作者cattt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:26:17