Ile danych jest kopiowanych, podczas zwracania std :: vector w funkcji i jak duża będzie optymalizacja, aby umieścić std :: vector w wolnym magazynie (na stercie) i zamiast tego zwrócić wskaźnik, tj. Jest:
std::vector *f()
{
std::vector *result = new std::vector();
/*
Insert elements into result
*/
return result;
}
bardziej wydajny niż:
std::vector f()
{
std::vector result;
/*
Insert elements into result
*/
return result;
}
?
c++
return-value
stdvector
Morten
źródło
źródło
f
?Odpowiedzi:
W C ++ 11 jest to preferowany sposób:
Oznacza to, że zwraca wartość.
W C ++ 11
std::vector
ma semantykę ruchu, co oznacza, że lokalny wektor zadeklarowany w funkcji zostanie przeniesiony po powrocie, aw niektórych przypadkach kompilator może wyeliminować nawet ruch.źródło
return std::move(v);
wyłączy ruch-elizję, nawet jeśli było to możliwe z justreturn v;
. Więc to drugie jest preferowane.Powinieneś zwrócić według wartości.
Standard ma specyficzną funkcję poprawiającą efektywność zwrotu wartości. Nazywa się to „elizją kopiowania”, a dokładniej w tym przypadku „nazwaną optymalizacją wartości zwracanej (NRVO)”.
Kompilatory nie muszą tego implementować, ale z drugiej strony kompilatory nie muszą implementować funkcji inlining (ani w ogóle wykonywać jakiejkolwiek optymalizacji). Ale wydajność standardowych bibliotek może być dość słaba, jeśli kompilatory nie optymalizują, a wszystkie poważne kompilatory implementują inlining i NRVO (i inne optymalizacje).
Po zastosowaniu NRVO nie będzie kopiowania w następującym kodzie:
Ale użytkownik może chcieć to zrobić:
Opcja Copy Elision nie zapobiega tutaj kopiowaniu, ponieważ jest to raczej przypisanie niż inicjalizacja. Jednak nadal powinieneś zwracać według wartości. W C ++ 11 przypisanie jest optymalizowane przez coś innego, zwanego „semantyką ruchu”. W C ++ 03 powyższy kod powoduje kopiowanie i chociaż teoretycznie optymalizator mógłby tego uniknąć, w praktyce jest to zbyt trudne. Więc zamiast tego
myvec = f()
w C ++ 03 powinieneś napisać to:Jest jeszcze jedna opcja, która ma zaoferować użytkownikowi bardziej elastyczny interfejs:
Następnie możesz również obsługiwać istniejący interfejs oparty na wektorach:
Może to być mniej wydajne niż istniejący kod, jeśli istniejący kod używa
reserve()
w sposób bardziej złożony niż tylko ustalona z góry kwota. Ale jeśli twój istniejący kod w zasadziepush_back
wielokrotnie odwołuje się do wektora, to ten oparty na szablonie kod powinien być równie dobry.źródło
Czas zamieścić odpowiedź na temat RVO , ja też ...
Jeśli zwracasz obiekt według wartości, kompilator często optymalizuje to, aby nie był konstruowany dwukrotnie, ponieważ zbędne jest konstruowanie go w funkcji jako tymczasowego, a następnie kopiowanie. Nazywa się to optymalizacją wartości zwracanych: utworzony obiekt zostanie przeniesiony zamiast kopiowania.
źródło
Popularnym idiomem sprzed C ++ 11 jest przekazanie referencji do wypełnianego obiektu.
Wtedy nie ma kopiowania wektora.
źródło
Jeśli kompilator obsługuje Named Return Value Optimization ( http://msdn.microsoft.com/en-us/library/ms364057(v=vs.80).aspx ), możesz bezpośrednio zwrócić wektor pod warunkiem, że nie ma:
NRVO optymalizuje nadmiarowy konstruktor kopiujący i wywołania destruktora, a tym samym poprawia ogólną wydajność.
W twoim przykładzie nie powinno być żadnych różnic.
źródło
A jeśli chcesz wydrukować to na main (), powinieneś to zrobić w pętli.
źródło
Mimo że „zwracanie przez wartość” może być przyjemne, jest to rodzaj kodu, który może prowadzić do błędu. Rozważ następujący program:
Powyższy błędny program nie wskaże żadnych błędów, nawet jeśli użyje się opcji raportowania GNU g ++ -Wall -Wextra -Weffc ++
Jeśli musisz podać wartość, to zamiast dwukrotnego wywołania vecFunc () zadziałałyby następujące czynności:
Powyższe również nie generuje żadnych anonimowych obiektów podczas iteracji pętli, ale wymaga możliwej operacji kopiowania (która, jak niektórzy zauważają, może zostać zoptymalizowana w pewnych okolicznościach. Ale metoda referencyjna gwarantuje, że żadna kopia nie zostanie utworzona. perform RVO nie zastąpi próby zbudowania najbardziej wydajnego kodu, jaki tylko możesz.Jeśli możesz podważyć potrzebę kompilatora do wykonania RVO, jesteś o krok do przodu.
źródło
źródło