2015-11-24 1 views
1

J'ai rencontré encore un autre problème avec std::thread & cette fois tout en appliquant std::move pour échanger 2 valeurs. Mon code dit: -en utilisant std :: move dans std :: thread

#include <iostream> 
#include <thread> 
using namespace std; 
void swapno (int &&a, int &&b) 
{ 
    int temp=move(a); 
    a=move(b); 
    b=move(temp); 
} 
int main() 
{ 
    int x=5, y=7; 
    cout << "x = " << x << "\ty = " << y << "\n"; 
// swapno (move(x), move(y)); // this works fine 
    thread t (swapno, move(x), move(y)); 
    t.join(); 
    cout << "x = " << x << "\ty = " << y << "\n"; 
    return 0; 
} 

Sortie: -

x = 5 y = 7 
x = 5 y = 7 

Maintenant, ce qui ne va pas dans cette méthode? Pourquoi un tel code montre-t-il un tel comportement? Comment puis-je le corriger?

+0

Le thread utilise une copie de 'x' et' y' qui ne lui sont pas réf. Vous pouvez passer le pointeur à 'x' et' y' à la place. – Jerome

+0

Les raisons sont les mêmes que pour votre question précédente. En outre, utilisez 'std :: swap'. – juanchopanza

+1

comment êtes-vous passé de "[vous devez envelopper dans un std :: ref] (http://stackoverflow.com/a/33895159)" pour utiliser &&? – Default

Répondre

3

Il est parce que le threadconstructor vous appelez

copies/déplace tous les arguments (à la fois l'objet de la fonction f et tous args ...) pour fil accessible stockage comme par la fonction:

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

Et std::decay enlèvera qualificatifs cv, ce qui inclut des références à valeur r.

Ainsi, lorsque std::thread est de copier/déplacer des arguments au stockage thread-accessible, il est déplacer essentiellement la construction son propreint s de ceux que vous avez fournis, et parce qu'un move sur un int est tout simplement une copie, lorsque vous effectuez swapno sur ses valeurs, vous le faites sur des copies.

Pour le corriger, utilisez std::ref, plus swap:

std::thread t ([](int& a, int& b){std::swap(a, b);}, std::ref(x), std::ref(y)); 
t.join(); 

Live Demo

+0

alors selon vous, nous ne pouvons pas utiliser 'rvalue references' avec' threads'? –

+1

@AnkitAcharya: Pas exactement. Vous ne devez pas utiliser les références rvalue lorsque vous souhaitez accéder aux données par la suite. Dans votre cas, 'std :: move' sur un int est inutile, mais si vous voulez peut-être donner au thread son propre vecteur' '(que vous avez construit dans le thread principal), alors' std :: move '' ce 'vecteur' est utile. – AndyG

0

En termes simples, constructeur de fil accepte/rvalues ​​aux temporaires les arguments passés à la fonction. Vous devez donc l'enrouler avec un argument reference_wrapper, qui est une valeur mais qui enveloppe la référence sous-jacente (ce que fait std :: ref).

Le code ci-dessous fait l'affaire avec std :: swap out of the box. Utiliser std :: swap comme argument de thread (ou std :: function) provoque une surcharge ambiguë (ce qui m'a surpris aussi).

int main(int argc, char* argv[]) 
{ 
    int x = 5, y = 7; 
    std::cout << "x(" << x << ")" << " y(" << y <<")" << std::endl; 
    void (*pf)(int& x, int& y) = std::swap<int>; 
    std::thread t1(pf, std::ref<int>(x), std::ref<int>(y)); 
    t1.join(); 
    std::cout << "x(" << x << ")" << " y(" << y <<")" << std::endl; 
    return 0; 
}