2016-05-26 12 views
1

Ich bin nicht sicher, ob ich das richtig verstehe diesen Code:Karte bewegen emplace mit lvalue

template<typename M> 
void add(M& m,int i, std::string s) 
{ 
    m.emplace(i,std::move(s)); 
} 

int main() 
{ 
    std::map<int,std::string> m; 
    add(m,1,"foo"); 
} 

Wenn add genannt wird, die std::string und die int kopiert werden. Die Methode emplace konstruieren Sie eine std::pair, die in die std::map (keine Kopie benötigt) bewegt wird. Aber die Kopie von int ist ein Lvalue, während die Kopie von std::string in einen rvalue umgewandelt wird, also welcher Konstruktor aufgerufen wird, um das std::pair zu konstruieren? Da ein Argument nicht verschoben werden kann, nehme ich an, dass hier eine zusätzliche Kopie stattfindet. Ist es richtig? Offensichtlich würde ich, wenn ich auch die Kopie von int zu einem rvalue überspiele, keine zusätzlichen Kopien erwarten.

Antwort

4

Dieser Konstruktor heißt:

template< class U1, class U2 > 
pair(U1&& x, U2&& y); 

In diesem Fall x und y sind nicht rvalue Referenzen sondern universal Referenzen. Lange Kurzgeschichte kurz, ein Lvalue (in diesem Fall die int) kollabiert aufgrund Ihrer std::move() zu einem Lvalue-Referenz und einem Rvalue (in diesem Fall die std::string) zu einem R-Wert Referenz.

Der instanziiert Konstruktor sieht wie folgt aus:

pair(int& x, std::string&& y); 

Scott Meyers erklärt es viel besser https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers

+0

Also wird das 'std :: pair' konstruiert, indem' int' kopiert und die 'std :: string' nach rechts verschoben wird? –

+0

@MarcoAgnese korrekt – imreal

0

Wenn add genannt wird, die std::string und die int kopiert werden.

The int kopiert, aber es gibt keine anfängliche std::string zu kopieren. Stattdessen wird s an Ort und Stelle in der Funktion selbst aus dem Stringliteral aufgebaut, dass Sie in sind vorbei.

daher der Konstruktor aufgerufen wird die std::pair

Wir mischen und anpassen können zu konstruieren. Es gibt eine Forwarding-Referenz Konstruktor Vorlage für std::pair:

template< class U1, class U2 > 
pair(U1&& x, U2&& y);   // since C++11, until C++14 

template< class U1, class U2 > 
constexpr pair(U1&& x, U2&& y); // since C++14 

Also in diesem Fall, sind wir pair<int&, std::string> rufen. Es gibt keine "zusätzliche Kopie".