应改用 std::move_only_function,因其仅要求 moveconstructible,专为移交即放弃的异步任务设计,不支持拷贝、target(),模板参数须显式带调用限定符。

遇到 error: use of deleted function 'X::X(const X&)' 就该换 std::move_only_function,不是代码写错了,是语义不匹配——它专为“移交即放弃”的异步任务设计,不能拷贝、不支持 target()、模板参数必须显式带限定符。
为什么 std::function 编译失败而 std::move_only_function 可以
典型错误是把捕获 std::unique_ptr 或 std::mutex 的 lambda 赋给 std::function。这不是你 lambda 写得不对,而是 std::function 强制要求被包装类型满足 CopyConstructible;而这类 lambda 会自动删除拷贝构造函数。
-
std::move_only_function只要求MoveConstructible,绕过拷贝检查 - 它底层不预留虚函数表项、不存引用计数字段,也没有拷贝逻辑——所以零开销,也无运行时兜底
- 能直接接:
[ptr = std::make_unique<int>(42)]() mutable { return *ptr; }</int> - 不能直接接可拷贝 lambda:
[x = 42]() { return x; },必须显式 move 构造:std::move_only_function<int>{std::move(lambda)}</int>
怎么声明、初始化和调用 std::move_only_function
它没有 make_move_only_function 辅助函数,也不支持 auto 推导模板参数。漏写任何调用限定符(noexcept、const、&、&&)都会导致类型不匹配,甚至调用时异常传播失控。
- 正确写法:
std::move_only_function<int const std::string noexcept></int>、std::move_only_function<void const></void>、std::move_only_function<double></double> - 错误写法:
std::move_only_function<void></void>(缺括号和参数列表)、auto f = std::move_only_function{}(模板参数无法推导)、std::move_only_function f = lambda(缺少模板参数) - 空初始化合法:
std::move_only_function<void> f;</void>,但调用前必须用if (f)检查是否为空 - 即使 lambda 声明为
const,只要内部std::move了捕获对象(如ptr.reset()),就只能进std::move_only_function
往 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成员 - 别把它塞进需要
CopyConstructible的老接口(如某些第三方回调注册函数),编译不过就是不过
最容易被忽略的是:捕获引用(如 [&x])本身不阻止编译,但 std::move 后原闭包失效,x 变成悬垂引用,运行时崩溃风险高;还有调用后原对象已失效,不能再用,也不能再判空复用。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











