2015-11-02 11 views
7

mam ten przykład:Dlaczego nie został wywołany konstruktor ruchu std :: string?

#include <string> 
#include <iostream> 

class Test { 
private: 
    std::string str; 
public: 
    Test(std::string &&str_) : 
     str(str_) 
    {} 

    const std::string &GetStr() 
    { 
     return str; 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    std::string there("1234567890"); 
    std::cout << "1. there: " << there << '\n'; 

    Test t1(std::move(there)); 

    std::cout << "2. there: " << there << '\n'; 
    std::cout << "3. there: " << t1.GetStr() << '\n'; 
} 

Daje wyświetlamy

$ ./a.out 
1. there: 1234567890 
2. there: 1234567890 
3. there: 1234567890 

ta używa gcc 5.1.1 w systemie Linux. Podczas gdy ciąg there pozostanie w ważnym, ale nieokreślonym stanie, po przeniesieniu, wydaje się, że ta implementacja przesuwa (i nie kopiuje) ciąg znaków, jeśli wywołany zostanie konstruktor ruchu std :: string.

jeśli mogę wymienić initalizer str(str_) z str(std::move(str_)) uzyskać ten wynik:

$ ./a.out 
1. there: 1234567890 
2. there: 
3. there: 1234567890 

to sugerować ruch konstruktor std :: string jest obecnie wykorzystywana, ale dlaczego nie std::string(std::string &&) jest wywoływana w moim pierwszym przykładzie?

Odpowiedz

6

Należy zrobić

public: 
    Test(std::string &&str_) : 
     str(std::move(str_)) 
    {} 

str_ mają nazwy, jest nazwany przedmiot, więc nie zostaną przekazane do dowolnej funkcji jak rvalue odniesień.

Wybór projektu dokonany przez Komitet Standardowy uniemożliwia jego traktowanie jako wartości rwart, więc nie można go nieumyślnie zmodyfikować. W szczególności: typ str_ do jest wartością lwartość do string, ale str_ nie jest uważana za wartość r, ponieważ jest to nazwany obiekt.

Musisz wyrazić swój zamiar, dodając połączenie pod numer std::move. Robiąc to, oświadczasz, że chcesz, aby str_ było rwartością i znasz wszystkie konsekwencje tego wyboru.

3

Ponieważ l-odniesienie zawsze wygrywa! Dlatego musisz wyraźnie określić std::move.

Dopuszcza się tworzyć odnośniki do odniesienia przez typ manipulacje w szablonach lub typedefs, w takim przypadku mają zastosowanie odniesienia zasady zwijanie: RValue odniesienie do odniesienia rvalue zapada do odniesienia rvalue, wszystkie inne kombinacje tworzą lwartości odniesienie :

typedef int& lref; 
typedef int&& rref; 
int n; 
lref& r1 = n; // type of r1 is int& 
lref&& r2 = n; // type of r2 is int& 
rref& r3 = n; // type of r3 is int& 
rref&& r4 = 1; // type of r4 is int&& 

Zrobione z here.

Powiązane problemy