2015-01-07 20 views
18

Perché chiamare std :: move su un oggetto const chiama il costruttore di copie quando viene passato a un altro oggetto? In particolare, il codicePerché chiamare std :: move su un oggetto const chiama il costruttore di copie quando viene passato a un altro oggetto?

#include <iostream> 

struct Foo { 
    Foo() = default; 
    Foo(Foo && x) { std::cout << "Move" << std::endl; } 
    Foo(Foo const & x) = delete; 
}; 

int main() { 
    Foo const x; Foo y(std::move(x)); 
} 

fallisce la compilazione con il messaggio:

g++ -std=c++14 test07.cpp -o test07 
test07.cpp: In function 'int main()': 
test07.cpp:10:36: error: use of deleted function 'Foo::Foo(const Foo&)' 
    Foo const x; Foo y(std::move(x)); 
            ^
test07.cpp:6:5: note: declared here 
    Foo(Foo const & x) = delete; 
    ^
Makefile:2: recipe for target 'all' failed 
make: *** [all] Error 1 

Certo, mi aspetto che a fallire perché non possiamo spostare un valore const. Allo stesso tempo, non capisco il percorso che il codice impiega prima di provare a chiamare il costruttore di copie. Significato, so che std::move converte l'elemento in un valore x, ma non so come procedono le cose dopo rispetto a const.

+7

Il 'const'ness del spostato l'oggetto non è cambiato, 'Foo const &&' non può legarsi a' Foo &&' così il compilatore prova ad accedere al costruttore di copie, che fallisce perché viene cancellato. – user657267

+2

Non sono esperto degli operatori di spostamento, ma forse è possibile chiamare lo spostamento su un valore 'const', ma il risultato da esso può essere accettato solo nel costruttore di copie, quindi il compilatore decide di chiamarlo. – BWG

+1

"Significato, so che std :: move converte l'elemento in un valore x" In realtà, non lo è. Restituisce un riferimento di rvalue all'articolo. –

risposta

35

Il tipo di risultato della chiamata std::move con un argomento T const è T const&&, che non può essere associato a un parametro T&&. La prossima corrispondenza migliore è il costruttore della copia, che viene eliminato, quindi l'errore.

Esplicitamente delete in una funzione non significa che non è disponibile per la risoluzione di sovraccarico, ma che se è effettivamente il candidato più valido selezionato dalla risoluzione di sovraccarico, allora si tratta di un errore del compilatore.

Il risultato ha un senso perché una costruzione mossa è un'operazione che ruba risorse dalla oggetto di origine, mutando così, quindi non si dovrebbe essere in grado di farlo a un oggetto const semplicemente chiamando std::move.

10

Il tipo di std::move(x) è Foo const&& che non può essere associato a Foo&&. Il ragionamento è lo stesso di un T const& che non è in grado di eseguire il binding a un T&. Tuttavia, è possibile che un costruttore prenda un numero Foo const&&. Molto probabilmente non sarà in grado di veramente mossa dati dell'oggetto corrispondente, ma, ad esempio, nel tuo esempio ci sono dati, vale a dire, il seguente codice funziona OK:

#include <iostream> 

struct Foo { 
    Foo() = default; 
    Foo(Foo &&) { std::cout << "Move\n"; } 
    Foo(Foo const&&) { std::cout << "Move const\n"; } 
    Foo(Foo const &) = delete; 
}; 

int main() { 
    Foo const x; Foo y(std::move(x)); 
} 
Problemi correlati