低版本MSVC中std::async编译失败,如何解决?
问题:如何让指定C++代码在MSVC 19.29版本下编译通过?
原代码
#include <vector> #include <algorithm> #include <thread> #include <future> #include <iostream> int main() { std::vector<int> v(1000); for(unsigned i = 0; i < v.size(); i++) { v[i] = i; } int bb = 2; std::cout << v.back() << std::endl; auto f = [&](int& x) {x = 2*x; bb=4; }; std::async(std::launch::async, std::for_each<decltype(v.begin()),decltype(f)>, v.begin(), v.end(), f); std::cout << v.back() << std::endl; std::cout << "bb: " << bb; return 0; }
编译失败情况
上述代码可在GCC、ICC、Clang及MSVC 19.32+版本正常编译(需链接-lpthread),但在MSVC 19.29版本下编译失败,报错信息如下:
example.cpp <source>(16): warning C4834: discarding return value of function with 'nodiscard' attribute C:/data/msvc/14.31.31108/include\future(314): error C2280: 'main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> &main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>::operator =(const main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> &)': attempting to reference a deleted function <source>(14): note: see declaration of 'main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>::operator =' <source>(14): note: 'main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> &main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>::operator =(const main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> &)': function was explicitly deleted C:/data/msvc/14.31.31108/include\future(309): note: while compiling class template member function 'void std::_Associated_state<_Ty>::_Set_value_raw(_Ty &&,std::unique_lock<std::mutex> *,bool)' with [ _Ty=main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> ] C:/data/msvc/14.31.31108/include\future(305): note: see reference to function template instantiation 'void std::_Associated_state<_Ty>::_Set_value_raw(_Ty &&,std::unique_lock<std::mutex> *,bool)' being compiled with [ _Ty=main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> ] C:/data/msvc/14.31.31108/include\future(722): note: see reference to class template instantiation 'std::_Associated_state<_Ty>' being compiled with [ _Ty=main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> ] C:/data/msvc/14.31.31108/include\future(720): note: while compiling class template member function 'std::_State_manager<_Ty>::~_State_manager(void) noexcept' with [ _Ty=main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> ] C:/data/msvc/14.31.31108/include\future(879): note: see reference to function template instantiation 'std::_State_manager<_Ty>::~_State_manager(void) noexcept' being compiled with [ _Ty=main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> ] C:/data/msvc/14.31.31108/include\future(860): note: see reference to class template instantiation 'std::_State_manager<_Ty>' being compiled with [ _Ty=main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37> ] <source>(17): note: see reference to class template instantiation 'std::future<main::<lambda_fa7e30e7ff267c277ebbd82c8a7f9e37>>' being compiled
解决方案
编译失败的核心原因是:旧版MSVC的std::async实现会尝试拷贝捕获了引用的lambda,而这类lambda的拷贝赋值运算符默认被删除,导致编译报错。以下是两种可行的修改方案:
方案一:用std::ref传递lambda(推荐)
将lambda通过std::ref包装后传递给std::async,同时去掉std::for_each的显式模板参数(让编译器自动推导更安全),修改后的代码行如下:
std::async(std::launch::async, std::for_each, v.begin(), v.end(), std::ref(f));
这种方式传递的是lambda的引用,避免了拷贝操作,旧版MSVC可以正确处理,同时保留原逻辑的正确性。
方案二:让lambda支持拷贝(不推荐)
手动为lambda添加拷贝构造和拷贝赋值运算符,但需要注意:原lambda捕获了局部变量的引用,拷贝后的lambda在异步线程中使用可能因变量生命周期问题导致悬空引用,引发未定义行为,因此仅在特殊场景下考虑此方案。
内容的提问来源于stack exchange,提问作者helios
相关产品推荐
相关产品推荐

