std::promise和std::future必须配对使用,future只能通过promise::get_future()获取,不可直接构造;set_value/set_exception只能调用一次,promise析构未设置值会触发broken_promise;wait不取值,get移动取值后future失效,wait_for仅探测状态不取值;async默认策略可能延迟执行,需显式指定launch::async确保并发。

std::promise 和 std::future 是一对,不能单独创建 future
你不能直接构造一个可写的 std::future;它必须由 std::promise 的 get_future() 方法返回。这是最常踩的坑:有人试图写 std::future<int> f{42};</int>,编译直接报错——std::future 的构造函数是删除的(deleted),只支持移动构造或从 promise::get_future() 获取。
正确做法是先声明 std::promise<t></t>,再调用其 get_future():
std::promise<int> p; std::future<int> f = p.get_future(); // ✅ 唯一合法方式
- 一旦调用过
get_future(),同一个promise就不能再调用第二次,否则抛std::future_error(错误码为future_errc::future_already_retrieved) -
promise和future可跨线程传递,但各自对象本身不共享状态——它们背后是同一份同步状态(shared state),由标准库内部管理 - 如果
promise被析构而从未设置值(set_value/set_exception),则future在等待时会抛std::future_error(broken_promise)
set_value() 必须在 promise 生存期内调用,且只能调用一次
std::promise::set_value() 是向关联的 future 写入结果的唯一入口。它不是线程安全的“多次写”,而是“一次性交付”——调用第二次会直接 terminate(C++17 起明确要求调用 std::terminate)。
典型误用场景:在异步任务里忘记检查是否已设置、或在异常路径中遗漏 set_exception():
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
std::promise<int> p;
auto f = p.get_future();
std::thread t([&p]{
try {
int res = compute_something();
p.set_value(res); // ✅ 正常路径
} catch (...) {
p.set_exception(std::current_exception()); // ✅ 必须覆盖异常路径
}
});
t.detach();
- 若
compute_something()抛异常但没进catch,或catch里忘了set_exception(),promise析构时触发broken_promise -
set_value()和set_exception()都是不可重入的;即使你用 mutex 包裹,也不能靠加锁绕过“只能调用一次”的语义限制 - 对于 void 类型的 promise(
std::promise<void>),调用的是set_value()(无参数),不是set_value(void{})
future::wait()、get()、wait_for() 的阻塞行为差异
std::future 提供三种等待方式,核心区别在于是否取值、是否阻塞、是否允许超时:
-
f.wait():纯阻塞等待结果就绪,不取值,返回后仍可调用get();适合只关心完成时机的场景(比如等后台初始化结束) -
f.get():阻塞直到就绪,然后**移动取出值**(对右值引用类型会触发移动),调用后该future变为无效状态(valid() == false);再次调用会抛std::future_error(no_state) -
f.wait_for(...):带超时的非阻塞等待,返回std::future_status(ready/timeout/deferred);注意它**不取值**,只是探测状态
常见错误:在 wait_for() 返回 timeout 后直接调用 get() ——这会导致无限阻塞,因为 get() 仍会等下去。正确做法是先确认 ready 再取:
if (f.wait_for(100ms) == std::future_status::ready) {
int val = f.get(); // ✅ 安全
} else {
// 处理超时
}
std::async 会自动管理 promise/future,但默认可能不启动新线程
很多人以为 std::async 就是“开个线程跑函数”,其实它的启动策略由 std::launch 策略决定。默认策略 std::launch::async | std::launch::deferred 允许实现延迟执行(即调用 get() 时才同步运行),这会让调试变得反直觉——你以为并发,其实串行。
- 想强制新开线程,显式传
std::launch::async:std::async(std::launch::async, []{...}) - 延迟模式下,
future的wait_for()永远返回deferred,且get()会立即同步执行函数体 -
std::async内部确实用promise/future实现,但你无法访问中间的promise对象——所以需要手动控制生命周期或异常传播时,别依赖它
真正需要精细控制(比如把 promise 交给某个回调、或跨多个异步步骤传递结果)时,还是得手写 promise/future 配对。async 只是语法糖,不是替代方案。

















