Visual-C++中std::promise::set_value执行后成员unique_ptr为空问题
问题根因
- MSVC STL的tuple实现缺陷:VS2019及更早版本的MSVC标准库中,对包含仅移动类型(如
std::unique_ptr)的tuple的完美转发、移动赋值逻辑存在已知bug。当std::forward<_Ty>(_Val)执行时,可能出现tuple部分成员被提前移动为空、未正确赋值到目标_Result的问题。Clang使用的libc++/libstdc++没有该实现问题,因此不会复现。 - 类型隐式转换问题:如果
std::promise声明的模板参数类型,和你传入set_value的实际tuple类型不完全匹配(比如自定义类型的cv限定符不一致、tuple长度/元素类型隐式可转换但不完全一致),MSVC会生成临时tuple对象完成转换,转换过程中可能错误触发部分成员的移动语义,导致最终_Result丢失mFoo的所有权。 - 调试器显示误差:部分版本的MSVC调试器在观测嵌套
unique_ptr的tuple结构时,会错误将有效指针显示为nullptr,你可以通过std::future::get获取结果后实际访问mFoo确认是否真的为空,排除调试器的干扰。
修复方案
- 升级到Visual Studio 2022 17.4及以上版本,微软已在新版MSVC STL中修复了大量tuple移动、转发相关的缺陷。
- 确保
std::promise的模板参数类型和传入set_value的参数类型完全一致,调用时显式使用std::move转移所有权,避免隐式转换:// 示例:promise类型与传入参数完全匹配,显式移动 std::promise<std::tuple<MyCustomType>> pr; std::tuple<MyCustomType> val = {MyCustomType{...}}; pr.set_value(std::move(val)); - 若暂时无法升级编译器,可以将存储用的tuple替换为自定义结构体,绕开MSVC tuple的实现问题。
内容的提问来源于stack exchange,提问作者Quentamia
相关产品推荐
相关产品推荐

