2012-12-26 11 views
7

Funkcja musi zwrócić dwie wartości do osoby dzwoniącej. Jaki jest najlepszy sposób wdrożenia?Czy RVO stanie się po powrocie std :: pair?

Wariant 1:

pair<U,V> myfunc() 
{ 
... 
return make_pair(getU(),getV()); 
} 

pair<U,V> mypair = myfunc(); 

Wariant 1.1:

// Same defn 
U u; V v; 
tie(u,v) = myfunc(); 

Opcja 2:

void myfunc(U& u , V& v) 
{ 
u = getU(); v= getV(); 
} 

U u; V v; 
myfunc(u,v); 

wiem z opcja2, brak kopii/przenosi ale wygląda brzydko. Czy będą jakieś kopie/ruchy w Opcjach 1, 1.1? Załóżmy, że U i V są dużymi obiektami obsługującymi operacje kopiowania/przenoszenia.

Q: Czy to teoretycznie możliwe za optymalizacje RVO/NRVO zgodnie z normą? Jeśli tak, czy został już zaimplementowany gcc lub jakikolwiek inny kompilator?

+1

Nic nie wiem o 'std :: pair', która mogłaby zahamować RVO/NRVO. Zazwyczaj dość łatwo jest przetestować, włączając w to konstruktor kopii, który powie ci, kiedy kopia się wydarzy. –

+1

g ++ implementuje RVO, które uniemożliwia skopiowanie pary, jednak nadal masz kopię u i v do pary. –

+0

Przeprowadziłem kilka testów i okazało się, że za pomocą g ++, który z nich był szybszy, zależało od tego, co było możliwe, oraz od złożoności konstruktorów kopii dla U i V. Jeśli szukasz tylko wydajności, myślę, że będziesz profilować go, aby ustalić, który jest najszybszy. –

Odpowiedz

8

Czy RVO stanie się po powrocie std::pair?

Tak, może.

Czy to się stało?

Nie, nie jest.


C++ 11 standard: Sekcja 12.8/31:

Kiedy pewne kryteria są spełnione, to implementacja wolno pominąć budowę kopia/ruch obiektu klasy, nawet jeśli konstruktor copy/move i/lub destruktor obiektu mają efekty uboczne.

Kopiowanie elision nie jest funkcją gwarantowaną. Jest to kompilator optymalizacji mogą wykonywać , gdy tylko mogą. Nie ma nic szczególnego w.r.t std::pair. Jeśli kompilator jest wystarczająco dobry, aby wykryć możliwość optymalizacji, zrobi to. Twoje pytanie jest specyficzne dla kompilatora, ale ta sama reguła odnosi się do std::pair jak do każdej innej klasy.

1

RVO lub Kopiuj elizja zależy od kompilatora, więc jeśli chcesz mieć RVO i uniknąć wywołanie konstruktora Kopiowanie najlepszym rozwiązaniem jest użycie wskaźników.

W naszych produktów używamy użyć wskaźników i pojemniki Boost wskaźnik, aby uniknąć kopiowania konstruktora. a to faktycznie zwiększa wydajność o około 10%.

Podążając za pytaniem, W opcji 1 konstruktor kopiowania U i V nie zostanie wywołany, ponieważ nie zwrócisz U lub V, ale zwrócisz obiekt std :: pair, więc zostanie wywołany konstruktor kopiowania i większość kompilatorów na pewno użyje RVO tutaj, aby tego uniknąć.

Dzięki Niraj Rathi

4

Podczas RVO nie jest gwarantowana, w C++ 11 funkcja jak zdefiniowano to wierzę, musi poruszać zwrotny w co najmniej, więc proponuję pozostawiając jaśniejszą definicję raczej niż wypaczenie, aby zaakceptować zmienne wyjściowe (o ile nie masz określonych zasad korzystania z nich).

Ponadto, nawet jeśli w tym przykładzie użyto usługi RVO, Twoje wyraźne użycie make_pair oznacza, że ​​zawsze będziesz mieć co najmniej jedną dodatkową parę, a tym samym operację przenoszenia. Zmień go, aby zwrócić wyrażenie inicjowane przez nawias klamrowy:

return { getU(), getV() }; 
Powiązane problemy