下面的代碼片段合法嗎?讓我擔心的是何時factorial呼叫fut_num可能已經超出范圍。
#include <future>
#include <vector>
#include <iostream>
//int factorial(std::future<int> fut) //works, because there is a move constructor
int factorial(std::future<int>&& fut)
{
int res = 1;
int num = fut.get();
for(int i=num; i>1; i--)
{
res *= i;
}
return res;
}
int main()
{
std::promise<int> prs;
std::vector<std::future<int>> vec;
{
std::future<int> fut_num{prs.get_future()};
vec.push_back(std::async(std::launch::async, factorial, std::move(fut_num)));
} //`fut_num` is out of range now.
prs.set_value(5);
for(auto& fut: vec)
{
std::cout << fut.get() << std::endl;
}
}
以及關于類似代碼片段的相同問題:
#include <future>
#include <vector>
#include <iostream>
//int factorial(std::future<int> fut) //works, because there is a move constructor
int factorial(std::future<int>& fut)
{
int res = 1;
int num = fut.get();
for(int i=num; i>1; i--)
{
res *= i;
}
return res;
}
int main()
{
std::promise<int> prs;
std::vector<std::future<int>> vec;
{
std::future<int> fut_num{prs.get_future()};
vec.push_back(std::async(std::launch::async, factorial, std::ref(fut_num)));
} //`fut_num` is out of range now.
prs.set_value(5);
for(auto& fut: vec)
{
std::cout << fut.get() << std::endl;
}
}
我對這些代碼片段的兩分錢:
1.前面的代碼片段是合法的,因為std::async副本std::move(fut_num)(即std::move(fut_num)通過值傳遞給std::async)。所以有一個本地fut_num當fcatorical被呼叫。
2.后一個是非法的,因為fut_num是作為參考傳遞的std::async。當fut_num超出范圍時,呼叫使用fut_num.
uj5u.com熱心網友回復:
第一個很好,第二個不行。
std::asyncwithstd::launch::async使用與建構式相同的呼叫執行緒函式的程序std::thread。兩者都有效執行
std::invoke(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...);
在新執行緒中,但auto(...)構造在呼叫執行緒的背景關系中執行。
這里F/Args...是具有相應轉發參考函式引數F&& f/的(其他)模板引數,Args&&... args并且auto具有新的 C 23 含義,它從引數創建衰減引數型別的純右值/臨時值。
請參閱[futures.async]/4.1。
這意味著將為存在于新執行緒中的所有引數構造未命名的副本,直到執行緒函式呼叫回傳之后。
因此std::move(fut_num),實際上會有另一個std::future<int>物件將從中移動構造fut_num并一直存在,直到執行緒結束執行。factorial將傳遞對此未命名物件的參考。
隨著std::ref(fut_num)您顯式繞過此機制,保護您免于傳遞對構造執行緒中物件的參考。
建構式仍會std::reference_wrapper<std::future<int>>從引數中生成型別的衰減副本,但該物件將僅包含fut_num在主執行緒中參考的參考。
std::invokestd::reference_wrapper然后將在傳遞到之前解包,factorial引數fut將fut_num在主執行緒中參考,然后在沒有任何同步的情況下銷毀,導致未定義的行為,因為它也在factorial函式中被訪問。
factorial無論哪種情況,引數是按參考還是按值都無關緊要。上述推理沒有任何改變。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/488652.html
