2013-08-09 18 views
8

Mam funkcji, która zwraca wektor lub Zestaw:Jak uniknąć kopię kiedy wrócę

set<int> foo() { 
    set<int> bar; 
    // create and massage bar 
    return bar; 
} 

set<int> afoo = foo(); 

W tym przypadku, tworzę tymczasową przestrzeń pamięci w funkcji foo(), a następnie przypisać do afoo przez skopiowanie. Naprawdę chcę uniknąć tej kopii, w jakikolwiek łatwy sposób I może to zrobić w C++ 11? Myślę, że to ma związek z rzeczą rvalue.

OK, aktualizacja pytania: jeśli mam zamiar zwrócić obiekt zdefiniowany przeze mnie, nie jest to wektor lub zestaw rzeczy, to znaczy, że powinienem zdefiniować konstruktor ruchu? podobnie jak:

class value_to_return { 
    value_to_return (value_to_return && other) { 
    // how to write it here? I think std::move is supposed to be used? 
    } 
} 

Pozdrawiam !!!

+4

To, co teraz masz, nie będzie żadnych kopii w C++ 11. Może wykonywać ruchy, ale nawet te prawie na pewno zostaną zoptymalizowane przez [N/RVO] (http://en.wikipedia.org/wiki/Return_value_optimization). –

+11

"jak uniknąć kopiowania po powrocie" - kompilacja z kompilatorem wydanym nie więcej niż 10 lat temu. –

+0

Jestem bardzo kuszony, aby ująć wszystkie odpowiedzi, które nie wspominają o ruchach/wartościach rowych. –

Odpowiedz

5

Zapoznaj się z return value optimization. Nowoczesny kompilator zoptymalizuje tę sytuację, a w prostych sytuacjach, takich jak te, żadna kopia nie zostanie wykonana na żadnym z głównych kompilatorów.

W zasadzie można również utworzyć obiekt poza funkcją, a następnie wywołać funkcję i przekazać obiekt do niej przez odwołanie. To byłby stary sposób uniknięcia kopii, ale teraz jest niepotrzebny i niepożądany.

-3

I zazwyczaj to obejść poprzez podpis funkcjonować jako

void foo(set<int> *x) 

Wystarczy przekazać je poprzez odniesienie lub drugiej opcji jest już wspomniano w komentarzu.

Edytuj: Zmieniłem typ argumentu, aby zilustrować, że x może zostać zmieniony.

 set<int> s; 
     foo(&s); 

Jest to zalecane tylko wtedy, gdy masz stary kompilator. Przypuszczam, że może tak być w przypadku niektórych projektów.

I lepiej będzie albo użyć semantyki ruchu za pomocą C++ 11. Lub śmiało zwróć kontener i zajrzyj do RVO w nowoczesnych kompilatorach.

+0

Głosuję na to, ponieważ jest to * jedyna * odpowiedź, która proponuje przekazanie parametru wyjściowego. Doskonałą odpowiedzią będzie RVO i przenoszenie konstruktorów. –

+8

Niemal pokusiłem się o oddanie głosu na _down_ za zaproponowanie parametrów wyjściowych. –

+0

@EdS .: Parametry wyjściowe są straszne. – Puppy

18

Modem kompilator C++ będzie realizować: podany typ T:

  • Jeśli T ma dostępną kopię lub przenieść konstruktora, kompilator może wybrać abstrahować kopię. Jest to tak zwany (nazwany) return value optimization (RVO), który został określony nawet przed C++ 11 i jest obsługiwany przez większość kompilatorów.
  • W przeciwnym razie, jeśli T ma wartość move constructor, T jest przenoszone (od C++ 11).
  • W przeciwnym razie, jeśli T ma konstruktora kopiowania, T jest kopiowane.
  • W przeciwnym razie zostanie wygenerowany błąd podczas kompilacji.
+0

Proszę, popraw mnie, jeśli się mylę, ale optymalizacja wartości zwracanej AFAIK działa tylko wtedy, gdy konstruujesz obiekt bezpośrednio w instrukcji return w następujący sposób: 'return (set ) (...);' Inteligentny kompilator może transformować kod w pytaniu do tej formy, ale dla bardziej złożonych funkcji wyobrażam sobie, że to nie zadziała. – cmaster

+0

@cmaster, w przypadku OP, RVO również będzie miało zastosowanie. Przeczytaj link wiki w mojej odpowiedzi na temat RVO. :) – billz

+0

@cmaster: Optymalizacja kopii w przypadku zwrócenia nazwanej zmiennej jest zwykle nazywana NRVO, nazwana optymalizacją wartości zwracanej i została zaimplementowana wiele lat temu przez większość kompilatorów. – JohannesD