2012-04-03 24 views
9

Il seguente programma non costruisce in VS11 beta, gcc 4.5, o clang 3,1std :: filo con mobile, argomento non copiabile

#include <thread> 
#include <memory> 

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

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

Questo perché il tipo argomento non è copiabile, ma la l'implementazione tenta di copiarlo.

Per quanto posso dire, questo programma è ben strutturato e dovrebbe funzionare. I requisiti per std :: thread sembrano implicare che gli argomenti mobili e non copiabili dovrebbero funzionare qui. In particolare, afferma che l'oggetto chiamabile e ciascun argomento devono soddisfare i requisiti MoveConstructible e che INVOKE(DECAY_COPY(std::forward<F>(f)),DECAY_COPY(std::forward<Args>(args))...) deve essere un'espressione valida.

In questo caso penso che l'espressione funziona a qualcosa di simile:

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))); 

E non credo che questo dovrebbe comportare una copia di p. gcc almeno può compilare questa espressione, sebbene VS11 no.

  1. Mi sbaglio sui requisiti e gli argomenti devono essere copiabili?
  2. Lo standard lascia un margine di manovra su questo problema perché le implementazioni copino gli argomenti?
  3. Oppure l'implementazione che ho provato non conforme?
+0

Sembra passare l'argomento thread per copia (come per la firma della funzione anonima). Il tipo di argomento non dovrebbe essere 'std :: unique_ptr &&' o 'const std :: unique_ptr &'? –

+2

@ André: Non esiste una cosa che passa per copia; passare l'argomento di _value_ verrà copiato o spostato a seconda che il chiamante passi un lvalue o un valore di rvalue. – ildjarn

+1

@ildjarn: scusate, intendevo "per valore", non "per copia". Mi è venuto in mente che passare gli argomenti in base al valore selezionerà il costruttore di mosse se ne è disponibile uno. –

risposta

14

Da 30.3.1.2, comma 3 e 4 del N3337:

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

Richiede: F e ogni Ti in Args deve soddisfare la MoveConstructible requisiti. INVOKE (DECAY_-COPY (std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...) (20.8.2) deve essere un'espressione valida.

Effetti: costruisce un oggetto di tipo thread. Il nuovo thread di esecuzione viene eseguito INVOKE (DECAY_-COPY (std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...) con le chiamate a DECAY_COPY in corso di valutazione nel thread di costruzione. Qualsiasi valore di ritorno da questa invocazione viene ignorato. [Nota: ciò implica che eventuali eccezioni non generate dall'invocazione della copia di f verranno generate nel thread di costruzione, non nel nuovo thread. -end note] Se l'invocazione di INVOKE (DECAY_COPY (std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...) termina con un'eccezione non rilevata, viene chiamato std :: terminate.

Quindi sì, questo dovrebbe funzionare. In caso contrario, questo è un bug nella tua implementazione.

Si noti che qualsiasi movimento/copia di parametri avverrà sul nuovo thread. Stai trasmettendo riferimenti a un altro thread, quindi devi assicurarti che esistano ancora fino all'avvio del thread.

+2

E funziona con g ++, dalla versione 4.7 – je4d

+0

E ora non riesco più a riprodurre l'errore in clang, anche se il codice che ho usato prima è in un repository di sorgenti e ho la riga di comando esatta nella mia storia. Suppongo che dovrei ricontrollare anche vs11. – bames53

+1

In realtà sembra che il problema fosse una vecchia versione di libC++ vs l'ultima. – bames53

3

In alternativa, e come standard std::thread linguaggio, è possibile passare un involucro di riferimento:

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

Questo crea un oggetto di tipo std::reference_wrapper<int>, che ha semantica di valore e avvolge un riferimento a un int (ie copiare il wrapper fa il riferimento al riferimento).

Problemi correlati