C++26前std::future不支持链式调用,因其为一次性对象、无回调接口且无法自动续接;强行模拟易致悬挂、死锁或泄漏,而C++20/23均未纳入then,仅C++26原生支持.then()实现安全链式异步。

直接用 std::future 和 std::promise 实现任务链(chaining)不可行——它们本身不支持自动续接,强行“链”容易导致悬挂、死锁或资源泄漏。
为什么 std::future 不支持直接 chaining
std::future 是一次性消费型对象:调用 get() 或 wait() 后状态失效;且它没有提供注册回调的接口。C++11/14 标准中,std::future 无法被多次等待,也不能在完成时自动触发下一个任务。
- 试图对同一
std::future多次调用get()→ 抛出std::future_error(错误码为std::future_errc::no_state) - 想在
future.wait()后立刻启动新任务?必须手动线程调度或轮询,失去异步意义 -
std::promise只负责单次set_value()/set_exception(),不感知下游依赖
可行替代方案:手动模拟 chain 的最小安全模式
若坚持只用标准库(不引入 std::execution 或第三方),可封装一个轻量级链式转发器:用 std::thread + std::promise 显式桥接前后任务,把前序 future 的结果作为参数传给后序函数。
关键点:
立即学习“C++免费学习笔记(深入)”;
- 每个环节用独立的
std::promise,避免复用失败 - 前序
future.get()必须在子线程中调用,否则阻塞主线程 - 异常必须显式捕获并调用
set_exception(),否则下游永远等不到结果 - 返回的
std::future对应的是“链末端”的 promise,不是中间态
示例节选(无异常传播简化版):
template<typename F, typename R = std::invoke_result_t<F, int>>
std::future<R> then(std::future<int> prev, F&& f) {
std::promise<R> p;
auto fut = p.get_future();
std::thread([p = std::move(p), f = std::forward<F>(f), prev = std::move(prev)]() mutable {
try {
auto val = prev.get(); // 阻塞在此,但在线程内
p.set_value(f(val));
} catch (...) {
p.set_exception(std::current_exception());
}
}).detach();
return fut;
}
std::future::then 在 C++20 中依然不存在
别被某些博客误导:std::future::then 并未进入 C++20 标准。提案 P0159 曾尝试加入,但因设计分歧(如 executor 绑定、异常语义、内存模型)被搁置。C++23 也未包含它。
- 部分编译器(如 MSVC)提供了实验性扩展,但行为不跨平台,不可用于生产
-
std::jthread(C++20)和std::stop_token解决的是协作取消,不解决 chaining - 真正可用的链式异步是
std::execution::schedule()+then()(C++23 Executors TS),但目前仅 libc++/libstdc++ 有极有限实现,且需开启实验性开关
实际项目中该怎么做
除非受严格约束必须纯标准库,否则优先考虑:
- 用
boost::asio::post()+boost::asio::deferred构建可组合的异步操作链 - 采用现代协程(
co_await)配合std::experimental::coroutine_handle或cppcoro库,写法接近同步逻辑 - 使用
absl::Future(Google Abseil)或folly::SemiFuture(Facebook Folly),它们专为 chaining 设计,支持错误传播、取消、Executor 绑定 - 自己封装时,务必让每个
promise的生命周期严格绑定到对应线程,避免std::promise被提前析构而调用set_*导致未定义行为
最易被忽略的一点:任务链不是语法糖,本质是控制流重定向。所有“自动链”背后都隐含 executor 调度策略、异常分发路径和内存所有权转移——漏掉任意一环,运行时就可能静默失败或卡死。


















