2013-03-05 51 views
16

我從C++ 11線程的非const引用無效初始化?

#include <thread> 
#include <iostream> 

using namespace std; 

void func(int& i){ 
    cout<<++i<<endl; 
} 

int main(){ 
    int x=7; 
    thread t(func,x); 
    t.join(); 
    return 0; 
} 

得到一個錯誤約

error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’

我明白,我不能這樣做,但thread(func, 4)x是一個變量,而不是暫時的。

我用gcc 4.7與-std = C++ 11 -pthread

爲什麼發生這個錯誤?

+0

看起來像實施中的錯誤。 – bames53 2013-03-05 23:24:50

+3

@ bames53,此行爲是標準要求的。 – 2013-03-06 00:30:56

+0

@JonathanWakely啊,我明白了。我快速瀏覽了'std :: thread'的定義,並看到了完美的轉發,但我並沒有停下來想起/考慮DECAY_COPY的意義。 – bames53 2013-03-06 01:07:12

回答

17

std::thread構造方法的規範說

Effects: Constructs an object of type thread. The new thread of execution executes INVOKE(DECAY_COPY(std::forward<F>(f)),DECAY_COPY(std::forward<Args>(args))...) with the calls to DECAY_COPY being evaluated in the constructing thread.

DECAY_COPY(X)手段調用decay_copy(x)這裏被定義爲:

template <class T> typename decay<T>::type decay_copy(T&& v) 
{ return std::forward<T>(v); } 

這意味着該論點「衰變「並且被複制,這意味着它們按價值被轉發並且失去任何cv資格。由於線程運行的目標函數想要通過引用獲取其參數,您會收到一個編譯器錯誤,指出引用無法綁定到按值傳遞的對象。

這是由設計決定的,因此默認情況下,傳遞給std::thread的局部變量通過值(即複製)而不是通過引用傳遞,以便新線程不會引用局部變量超出範圍的懸掛引用,導致未定義的行爲。

如果您知道通過引用傳遞變量是安全的,那麼您需要明確地使用reference_wrapper,它不會受到「衰減」語義的影響,並會通過引用目標對象來轉發變量。您可以使用std::ref創建reference_wrapper

+0

+1不錯的完整答案Jonathan – 2013-03-06 00:29:04

+2

我真的很好奇,爲什麼標準沒有給我們std :: invoke和std :: decay_copy ...... – Xeo 2013-03-06 00:52:43

+0

謝謝!我從來沒有聽說過decay_copy。 – 2013-03-06 16:27:18

15

包裝xstd::ref當您創建線程。

如果您每次創建std::thread時都會引用所有變量,請考慮會發生什麼情況:如果您傳遞了堆棧局部變量,它將成爲懸掛引用,並且如果線程超出該自動存儲變量的範圍。這在實踐中會發生很多,並導致很多錯誤。相反,默認情況下,std::thread需要(通過完美轉發的方式)所有參數(包括變量)的值。

通過傳遞的x線程局部左值拷貝調用你的工人功能時,std::future可以默默的工作,但是這將是非常令人迷惑:工人的任務將編輯x,你以爲你按引用傳遞,而且止跌在任務之外的x中不會出現。相反,它有助於給你那個錯誤信息。你應該感謝你的幸運之星!

爲了表明你確實真的不想要有價值的東西,可以將它包裝在std::ref中,現在它一直作爲參考傳遞給工作函數。在這種情況下,您有責任管理引用的生命週期,以便所引用的數據至少與std::future的工作任務需要的持續時間相同。

+0

thread t(func,ref(x));像魅力一樣工作,謝謝! – 2013-03-05 23:13:43

+7

這將解決錯誤,但問題是爲什麼它是一個錯誤。 – juanchopanza 2013-03-05 23:14:58

+2

@juanchopanza真實 - 我在我的手機上,所以我迅速解決了Alex的問題。現在添加了細節。 – Yakk 2013-03-06 00:42:41