差分

2011-02-25 44 views
30

這是例如:差分

#include<iostream> 
#include<thread> 
using namespace std; 

void f1(double& ret) { 
    ret=5.; 
} 

void f2(double* ret) { 
    *ret=5.; 
} 

int main() { 
    double ret=0.; 
    thread t1(f1, ret); 
    t1.join(); 
    cout << "ret=" << ret << endl; 
    thread t2(f2, &ret); 
    t2.join(); 
    cout << "ret=" << ret << endl; 
} 

並且輸出是:

ret=0 
ret=5 

編譯用gcc 4.5.2,具有和不具有-O2

這是預期的行爲?

這個程序數據競賽是免費的嗎?

thread t1(f1, std::ref(ret)); 

更多信息here

如果你想通過參考std::thread則必須將他們每個人在std::ref傳遞參數謝謝

回答

63

std::thread的構造函數推導參數類型並按值存儲它們。

C++模板函數參數類型演繹機制從T&類型的參數中推導出類型T。因此,std::thread的所有參數都按值傳遞,因此f1()f2()總是獲得副本。

如果你堅持要用一個參考,使用包裹或boost::ref()std::ref()參數:

thread t1(f1, boost::ref(ret)); 

或者,如果你喜歡簡單,通過一個指針。這是boost::ref()std::ref()爲你背後的場景。

+0

正確答案。 Upvoted。 – 2011-02-25 11:58:51

+0

這真的幫助了我,謝謝+1。如果這個消息仍然會被任何人注意到,我可以問一下'thread'使用這個機制的原因。這與c有關,還是它有一個完全不同的原因? – patrik 2014-05-15 07:01:44

+1

@patrik與存儲引用或指針相比,值語義(複製)是安全的。當引用的對象被銷燬時,引用或指針可能會變得懸而未決。這就是爲什麼'std :: bind'和'std :: thread'默認存儲參數的值,你必須明確地要求它做一個不太安全的事情。 – 2014-05-15 08:39:22

5

6

在這些情況下,您需要明確的std::ref()(或boost::ref())實際上是一個非常有用的安全功能,因爲傳遞參考本質上可能是一件危險的事情。

對於非const引用,通常存在傳遞局部變量的危險,其中const引用可能是臨時的,並且當您創建一個要在不同線程中調用的函數時(並且通常使用綁定,通常是一個函數稍後/以異步方式調用),那麼您將面臨對象不再有效的巨大危險。

綁定看起來很整齊,但這些錯誤是最難找到的,因爲錯誤被捕獲的地方(即在調用函數中)與錯誤發生的位置不同(在綁定時),它可以是很難弄清楚當時正在調用哪個函數,以及它在哪裏被綁定。

當您在作爲參考傳遞的變量範圍內加入線程時,它在您的實例中是安全的。因此,當你知道這是一種傳遞參考的機制。

這不是我希望看到改變的語言的一個特徵,特別是因爲可能有很多現有的代碼依賴於它做一個副本,如果它只是通過引用自動引用會破壞(然後需要一種強制拷貝的明確方式)。