2013-04-13 11 views
5

Perché nel seguente codice di esempio, l'oggetto viene copiato due volte? Secondo il costruttore di documentazione della classe thread, copia tutti gli argomenti sull'archiviazione thread-locale, quindi abbiamo un motivo per la prima copia. Che dire del secondo?std :: thread Perché l'oggetto viene copiato due volte?

class A { 
public: 
    A() {cout << "[C]" << endl;} 
    ~A() {cout << "[~D]" << endl;} 
    A(A const& src) {cout << "[COPY]" << endl;} 
    A& operator=(A const& src) {cout << "[=}" << endl; return *this;} 

    void operator()() {cout << "#" << endl;} 
}; 

void foo() 
{ 
    A a; 
    thread t{a}; 
    t.join(); 
} 

uscita dall'alto:

[C] 
[COPY] 
[COPY] 
[~D] 
# 
[~D] 
[~D] 

Edit: Ebbene sì, dopo l'aggiunta di movimento costruttore:

A(A && src) {cout << "[MOVE]" << endl;} 

L'output è simile a questo:

[C] 
[COPY] 
[MOVE] 
[~D] 
# 
[~D] 
[~D] 
+2

Solo una piccola correzione: gli argomenti non vengono copiati in ** archiviazione locale locale **, ma nello stack del nuovo thread. L'archiviazione locale del thread è un animale completamente diverso; una variabile locale del thread è, in sostanza, una variabile globale per thread, accessibile da qualsiasi funzione nel thread, con una copia distinta in ogni thread. –

+0

In effetti, secondo '[COPY]' è '[MOVE]', ma non puoi vederlo perché non hai implementato alcun costruttore di move. – soon

+0

Nel caso precedente, il secondo [COPIA] è una copia. Solo se fornisci un costruttore di mosse o lo dichiari esplicito con = default ottieni la mossa. – Klaus

risposta

3

Per qualsiasi cosa si desidera spostare o evitare le copie, preferire i costruttori di movimento e std::move.

Ma perché questo non accade automaticamente per me?

Il passaggio in C++ è conservativo. Solitamente si muoverà solo se scrivi esplicitamente std::move(). Ciò è stato fatto perché spostare la semantica, se estesa oltre circostanze molto esplicite, potrebbe interrompere il codice precedente. Le mosse automatiche sono spesso limitate a un insieme di circostanze molto attente per questo motivo.

Per evitare copie in questa situazione, è necessario spostare a utilizzando std::move(a) (anche quando lo si passa in std::thread). Il motivo per cui esegue una copia la prima volta è perché std :: thread non può garantire che il valore esisterà dopo aver terminato la costruzione di std :: thread (e non lo si è spostato in modo esplicito). Così, farà la cosa sicura e farà una copia (non prendere un riferimento/puntatore a ciò che hai passato e memorizzarlo: il codice non ha idea se lo manterrai o meno).

Avere sia un costruttore di spostamenti che l'uso di std::move consentirà al compilatore di spostare la propria struttura in modo ottimale ed efficiente. Se si utilizza VC++ (con CTP o meno), è necessario scrivere esplicitamente il costruttore di movimento, altrimenti MSVC (anche a volte erroneamente) dichiarerà e utilizzerà un costruttore di copia.

0

prova con: thread t {std :: m ove (a)};

Problemi correlati