std::move_only_function是唯一能合法接住不可拷贝异步任务的类型,它仅要求MoveConstructible,绕过std::function强制CopyConstructible的限制,且需手写完整模板签名、显式move、空值检查。

编译失败时别硬套 std::function,std::move_only_function 是唯一能合法接住不可拷贝异步任务的类型——它不是“更轻量的替代品”,而是语义上唯一正确的选择。
error: use of deleted function 'X::X(const X&)' 就该换 std::move_only_function
这个错误不是你 lambda 写错了,是 std::function 在构造时就拒绝了 move-only 类型:它强制要求 CopyConstructible,而捕获 std::unique_ptr、std::mutex 或自定义 non-copyable 类型的 lambda 会自动删除拷贝构造函数。
-
std::move_only_function只要求MoveConstructible,绕过拷贝检查,且不预留虚函数表项或引用计数字段 - 能直接接:
[ptr = std::make_unique(42)]() mutable { return *ptr; } - 不能直接接:
[x = 42]() { return x; }(可拷贝 lambda),必须显式std::move_only_function{std::move(lambda)} - 捕获引用如
[&x]本身不阻止拷贝,但 move 后原闭包仍持有悬垂引用,运行时崩溃风险高
std::move_only_function 的模板参数必须手写完整签名
它不提供 make_move_only_function 辅助函数,也不支持 auto 推导。漏写任何调用限定符(noexcept、const、&、&&)都会导致类型不匹配,甚至调用时异常传播失控。
- 正确:
std::move_only_function、std::move_only_function - 错误:
std::move_only_function(缺括号和参数列表)、std::move_only_function(空模板参数) - 即使被封装函数带
noexcept,而模板参数没写,operator()调用可能意外抛出,破坏预期
往 std::vector 存或传参时必须显式 std::move
所有“转移所有权”的操作都强制显式 std::move,编译器不会隐式转换,也不会给你运行时兜底——漏掉就直接编译失败。
-
std::vector<:move_only_function>> tasks;→tasks.push_back(std::move(task));,不能写tasks.push_back(task); - 函数参数建议用右值引用:
void enqueue(std::move_only_function,避免入口处尝试拷贝&&task) - 类成员含
std::move_only_function时,移动赋值操作符必须手动定义为= default或逐个std::move
空值检查和调用后状态管理最容易被忽略
std::move_only_function 支持空初始化(如 std::move_only_function),但调用前必须用 if (f) 检查是否为空;一旦 move 出去,原对象进入有效但未指定状态,再次调用触发未定义行为。
- 错误姿势:
task(); task();—— 第二次调用未定义;std::move(task)();也不行,move 后不能再调用 - 如果需要多次执行,闭包内部自己管理状态(如用
mutable+ 成员变量),而不是靠外部重复 move - 它不支持
target()或target_type(),move-only 类型擦除后无法安全还原原始类型,这部分能力被主动舍弃
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











