2013-01-16 9 views
10

W artykule Artima na temat wartości rvalue w C++ (http://www.artima.com/cppsource/rvalue.html) znajdują się słowa: Dlatego konieczne jest, aby powiedzieć przenieść (x) zamiast tylko x przy przekazywaniu do klasy bazowej. Jest to kluczowa cecha bezpieczeństwa semantyki ruchu zaprojektowana, aby zapobiec przypadkowemu przemieszczeniu się dwa razy od nazwanej zmiennej.Wartość odniesienia wartości RV: Dlaczego wartości rvalue nie są domyślnie przenoszone?

Nie mogę myśleć o sytuacji, w której może wystąpić taki podwójny ruch. Czy możesz dać przykład tego? Innymi słowy, co pójdzie nie tak, jeśli wszyscy członkowie T&& będą referencjami rwartości, a nie tylko referencjami?

Odpowiedz

16

Rozważmy następujący scenariusz:

void foo(std::string x) {} 
void bar(std::string y) {} 

void test(std::string&& str) 
{ 
    // to be determined 
} 

Chcemy wywołać foo z str, potem bar z str, zarówno o tej samej wartości. Najlepszym sposobem na to jest:

foo(str); // copy str to x 
bar(std::move(str)); // move str to y; we move it because we're done with it 

Byłoby błędem, aby to zrobić:

foo(std::move(str)); // move str to x 
bar(std::move(str)); // move str to y...er, except now it's empty 

Ponieważ po pierwszym ruchu wartość str jest nieokreślona.

Tak więc w projekcie odniesień rvalue nie ma tego niejawnego ruchu. Gdyby tak było, nasz najlepszy sposób powyżej nie działałby, ponieważ pierwsza wzmianka o str byłaby zamiast tego.

3

Tak jak ja to widzę, że gdybyśmy mieli jakieś odniesienia RValue X:

T&& x = ...; 

i nazwaliśmy niektórych funkcji za pomocą przycisków X jako parametru:

f(x) 

Musimy jakoś powiedzieć f czy może on uszkodzić x (lub "przejąć na własność x" lub "jest ostatnim klientem, który używa x").

Jednym ze sposobów, aby zaprojektować to byłoby zakwalifikować każdą rozmowę:

f(yours_now(x)) // ok to damage 
f(still_mine(x)) // dont damage 

i sprawiają, że bezwarunkowe wezwanie nielegalne.

Innym sposobem byłoby zrobić jeden sposób domyślny:

Albo:

f(yours_now(x)) // ok to damage 
f(x) // dont damage 

lub

f(x) // ok to damage 
f(still_mine(x)) // dont damage 

Więc jeśli zgodzimy kwalifikacyjna każde użycie jest zbyt nieporęczne i powinniśmy domyślnych w jedną stronę, która jest najlepsza? Cóż, spójrzmy na koszt przypadkowego wybrania domyślnego w obu przypadkach:

W pierwszym przypadku można było uszkodzić, ale my przypadkowo powiedzieliśmy, że nie było. W tym przypadku tracimy wydajność, ponieważ została wykonana niepotrzebna kopia, ale poza tym nic wielkiego.

W drugim przypadku nie można uszkodzić obiektu, ale przypadkowo o tym mówiliśmy.Może to spowodować trudny do wykrycia błąd logiczny w programie, ponieważ x jest teraz w stanie uszkodzonym, jak zwraca f, ale autor oczekiwał, że tak się nie stanie.

Pierwszy przypadek został wybrany, ponieważ jest "bezpieczniejszy".

Powiązane problemy