std::function编译失败是因为其要求CopyConstructible而捕获unique_ptr的lambda删除了拷贝构造,std::move_only_function仅需MoveConstructible且零开销;它无辅助函数、不隐式转换、需显式声明签名与std::move,调用前须判空且move后原对象失效。

直接用 std::move_only_function 存捕获 std::unique_ptr、std::mutex 或自定义 non-copyable 类型的 lambda,是唯一合法且零开销的方案;试图塞进 std::function 会立刻编译失败,不是写法问题,而是语义冲突。
为什么 std::function 编译不过,而 std::move_only_function 可以
错误信息通常是 error: use of deleted function 'X::X(const X&)' —— 这不是你的 lambda 写错了,是 std::function 强制要求目标类型满足 CopyConstructible,而捕获 std::unique_ptr 的 lambda 自动删除了拷贝构造函数。
std::move_only_function 只要求 MoveConstructible,绕过该约束。它不存拷贝逻辑,也不预留虚函数表项或引用计数字段。
- 能接:
[ptr = std::make_unique<int>(42)]() mutable { return *ptr; }</int> - 不能直接接:
[x = 42]() { return x; }(可拷贝 lambda),必须显式 move 构造:std::move_only_function<int>{std::move(lambda)}</int> - 捕获引用如
[&x]本身不阻止拷贝,但 move 后原闭包失效,运行时崩溃风险高
声明和初始化必须显式写出完整调用签名
std::move_only_function 没有 make_move_only_function 辅助函数,也不能靠 auto 推导。模板参数必须包含 noexcept、const、& 等修饰符,否则 operator() 行为可能不匹配。
立即学习“C++免费学习笔记(深入)”;
- 正确:
std::move_only_function<void noexcept></void>、std::move_only_function<int const></int> - 错误:
std::move_only_function<void></void>(缺少括号和参数列表) - 若被封装函数带
noexcept,而模板参数没写,调用时可能触发异常传播,破坏预期
往 vector 或传参时必须显式 std::move
所有“转移所有权”的操作都强制显式 std::move,编译器不会帮你隐式转换。漏掉就报错,没有运行时兜底。
-
std::vector<:move_only_function>> tasks;</:move_only_function>→tasks.push_back(std::move(task));,不能写tasks.push_back(task); - 函数参数建议用右值引用:
void enqueue(std::move_only_function<void> &&task)</void>,避免入口处尝试拷贝 - 类成员含
std::move_only_function时,移动赋值操作符必须手动定义为= default或逐个std::move
空值检查和调用后状态管理容易被忽略
std::move_only_function 支持 nullptr 初始化,但调用前必须检查:if (f) f();,否则未定义行为。更关键的是:一旦 move 出去,原变量进入有效但未指定状态,再次调用(哪怕只是 f())就是未定义行为。
- 错误姿势:
task(); std::move(task)();—— 第二次已失效 - 正确姿势:把状态管理交给闭包内部,比如用
mutable+ 成员变量实现多次执行逻辑 - 异步 API 接收方必须明确承担所有权,即参数类型应为
std::move_only_function<void> &&</void>,而非const&或值传递


















