2012-12-23 13 views
11

Powiel możliwe:
What happens if I return literal instead of declared std::string?zrozumienie C++ 11 rvalues, przenieść semantykę i wydajność

Rozważmy następujący kod

1| string getName() { 
2|  return "meme"; 
3| } 
4| 
5| string name = getName(); 

getName() funkcja zwraca obiekt tymczasowy. W języku C++ 03 rozumiem, że konstruktor kopii "string" zostaje wywołany, a obiekt tymczasowy zostaje zniszczony. W rzeczywistości wydaje się, że kompilator (co najmniej w gcc 4.7) optymalizuje wiersz 5, nie tworząc obiektu "nazwa", lecz zastępując go samym obiektem tymczasowym i nie niszcząc obiektu tymczasowego (próbowałem z klasą MyVector, a nie std :: string).

Jak zdefiniowano w standardach C++ 11,
1. Czy funkcja getName() zwraca wartość r?
2. W linii 5 powyżej, który konstruktor ciągu zostanie wywołany (przenieść lub skopiować)? Czy powinienem koniecznie wywołać std :: move(), aby konstruktor ruchu został wywołany?
3. Czy z semantyką ruchu jest ona mniej wydajna niż optymalizacja "kopiowania" dostarczona przez kompilator?

+2

To byłaby _copy elision _... –

+0

@ K-ballo dzięki za oświecenie mnie. –

+0

Dodawanie numerów linii wygląda niesamowicie! Nigdy wcześniej tego nie widziałem =) – qwertz

Odpowiedz

18
  1. Funkcje NIE cofnięcie rvalues ​​lub lwartościami. Kategorie wartości mają zastosowanie do wyrażeń. Zatem wyrażenie, które może pełnić funkcję, może być rwartością lub lwartością. W tym przypadku wyrażenie getName() jest wyrażeniem rvalue, ponieważ funkcja zwraca obiekt po wartości. Wynika to z §5.2.2/10:

    Wywołanie funkcji jest lwartością jeśli typ wynik jest lwartością typ referencyjny lub odniesienie RValue funkcjonować typu An xvalue jeśli typ wynik jest odniesienie do RValue typ obiektu i wartość prinalue inaczej.

    Typ wyników funkcji nie jest wartością l-wartości ani wartością rwartości, więc wywołanie funkcji jest wartością. wyrażeń prvalue są podzbiorem wyrażeń rvalue.

  2. Zostanie użyty konstruktor ruchu (chyba że zostanie usunięty, co może być). To dlatego, że getName() jest wartością r, więc konstruktor z std::string, który przyjmuje wartość odniesienia rvalue, lepiej pasuje do argumentu. Zwróć uwagę, że nawet jeśli konstrukcja ruchu zostanie usunięta, konstruktor ruchu musi być nadal dostępny. Oznacza to, że kod musi być kompilowany, nawet jeśli nie zostanie usunięty.

  3. Ogólnie rzecz biorąc, optymalizacja kopiowania lub przenoszenia jest całkowicie eliminowana z kopiowania lub przenoszenia. Oczywiście jest to szybsze niż wykonanie ruchu. Jeśli ruch zostanie usunięty, dosłownie nic się nie dzieje. Dla tego ruchu nie będzie emitowany kod. Kompilator osiąga to przez bezpośrednie skonstruowanie obiektu w lokalizacji, do której zostanie skopiowany lub przeniesiony.

Warto wspomnieć, że może to być również zoptymalizowana równoważnie:

string getName() { 
    std::string str("meme"); 
    return str; 
} 

string name = getName(); 

Tutaj dwa ruchy będzie pomijana (z udziałem co jest powszechnie znany jako Named Return Value Optimization). Należy wziąć pod uwagę dwie kwestie. Najpierw return str; spełnia kryteria elizji kopiowania/(§12.8/31):

tym elizji operacji kopiowania /, zwany kopii wyrzutnia jest dozwolone w następujących warunkach (które mogą być łączone wyeliminować wielokrotne kopie):

  • w instrukcji return w funkcji o typie klasy powrotnej, gdy wyrażenie jest nazwą nieulotnej automatycznym obiektu (inne niż funkcja lub parametr catch-klauzula) z ten sam typ bez cv, jak typ zwracany przez funkcję, operacja kopiowania/przenoszenia może zostać pominięta przez skonstruowanie automatycznego obiektu int o wartości powrotu z funkcji
  • ...

Po drugie jest to, że chociaż str jest lwartością, to nadal będzie przeniesiony z ponieważ pasuje szczególny przypadek podany przez normę (§12.8/32):

Kiedy kryteria elizji operacji kopiowania są spełnione lub zostaną spełnione za wyjątkiem faktu, że obiekt źródłowy jest parametr funkcji, a obiekt ma zostać skopiowany został wyznaczony przez lwartością, rozdzielczość przeciążenie aby wybrać konstruktor dla kopii jest najpierw wykonywany tak, jakby obiekt był oznaczony jako b y wartość r.