2012-04-03 83 views
9

下面的程序不會在VS11 beta製造,GCC 4.5,或3.1鏗鏘的std ::螺紋,可移動的,不可複製的參數

#include <thread> 
#include <memory> 

int main() { 
    std::unique_ptr<int> p; 
    std::thread th([](std::unique_ptr<int>) { 

    },std::move(p)); 
    th.join(); 
} 

這是因爲參數類型是不可拷貝,但實現嘗試複製它。

據我所知,這個程序是完好的,應該工作。對std :: thread的要求似乎意味着可移動的,不可複製的參數應該在這裏工作。具體而言,它表示可調用對象和每個參數應滿足MoveConstructible要求,且INVOKE(DECAY_COPY(std::forward<F>(f)),DECAY_COPY(std::forward<Args>(args))...)應爲有效表達式。

在這種情況下,我想表達出來的作品喜歡的東西:

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

std::unique_ptr<int> p; 
auto f = [](std::unique_ptr<int>) {}; 

decay_copy(f)(decay_copy(std::move(p))); 

而且我不認爲這應該涉及p副本。 gcc至少可以編譯這個表達式,儘管VS11沒有。

  1. 我是否錯誤的要求和參數必須是可複製的?
  2. 對於實現複製參數,標準是否在這個問題上留有餘地?
  3. 或者我嘗試不符合?
+0

您似乎通過複製傳遞線程參數(按照匿名函數簽名)。參數類型不應該是'std :: unique_ptr &&'或'const std :: unique_ptr &'? – 2012-04-03 21:36:39

+2

@安德烈:沒有任何東西可以通過複製傳遞;通過_value_傳遞參數將根據調用者是傳遞左值還是右值來複制或移動。 – ildjarn 2012-04-03 21:47:22

+1

@ildjarn:對不起,我的意思是「按價值」,而不是「通過複製」。它忽略了按值傳遞參數將選擇移動構造函數(如果有)。 – 2012-04-03 22:23:49

回答

14

從30.3.1.2,第3段和N3337的4:

template <class F, class ...Args> explicit thread(F&& f, Args&&... args);

要求FArgs每個Ti應滿足MoveConstructible要求。 INVOKE (DECAY_-COPY (std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)(20.8.2)應是一個有效的表達式。

效果:構造一個線程類型的對象。執行的新線程執行INVOKE (DECAY_-COPY (std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...),並在構造線程中調用DECAY_COPY進行評估。此調用的任何返回值都將被忽略。 [注意:這意味着在調用f時不會引發的異常將在構造線程中拋出,而不是在新線程中拋出。 - 注意]如果INVOKE (DECAY_COPY (std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)的調用以未捕獲的異常終止,則應調用std :: terminate。

所以是的,這應該工作。如果沒有,那麼這是您實施中的一個錯誤。

請注意,任何參數移動/複製都將發生在新線程上。您將引用傳遞給另一個線程,因此您需要確保它們在該線程啓動之前仍然存在。

+2

它與g ++一起工作,從4.7版本開始 – je4d 2012-04-03 22:25:30

+0

現在我不能再在clang中重現錯誤,即使我之前使用的代碼位於源代碼庫中,並且我的歷史記錄中包含確切的命令行。我想我應該重新檢查vs11。 – bames53 2012-04-04 00:55:21

+1

實際上,它看起來像問題是舊版本的libC++ vs最新版本。 – bames53 2012-04-04 00:56:54

3

作爲替代方案,併爲標準std::thread成語,可以傳遞一個參考包裝:

int p; 
std::thread([](int & x) { /* ... */ }, std::ref(p)); 

這創建std::reference_wrapper<int>類型的對象,其具有價值的語義和換行到一個int的參考(即複製包裝別名參考)。

相關問題