2016-09-15 15 views
11

Próbuję uniknąć argumentów wyjściowych w moich funkcjach. Stara funkcja:Funkcja zwraca krotkę utworzoną z wektorów

void getAllBlockMeanError(
    const vector<int> &vec, vector<int> &fact, vector<int> &mean, vector<int> &err) 

Tutaj vec argumentem jest wejście, fact, mean i err są wyprowadzane argumentem. Próbowałem wyjściowym argumentem grupy do jednej krotce:

tuple< vector<int>, vector<int>, vector<int> > 
            getAllBlockMeanErrorTuple(const vector<int> &vec) 
{ 
    vector<int> fact, mean, err; 
    //.... 
    return make_tuple(fact, mean, err); 
} 

Teraz mogę nazwać nową funkcję z:

tie(fact, mean, err) = getAllBlockMeanErrorTuple(vec); 

wygląda czystsze do mnie. Chociaż mam pytanie, w jaki sposób działa przypisanie równe tie(fact, mean, err)? Czy robi głęboką kopię lub ruch? Ponieważ fact, mean i err wewnątrz getAllBlockMeanErrorTuple zostaną zniszczone, mam nadzieję, że wykona ruch zamiast głębokiej kopii.

+0

Nie jestem pewien, ale myślę, że jak napisane będzie kopiować wektory. Jeśli przeniesiesz wektory do 'make_tuple()', to powinny one zostać przeniesione. – Andy

+5

Chciałbym użyć 'struct Result {wektor fakt; wektor średni; wektor err; }; 'zamiast krotki, aby mieć lepsze nazewnictwo dla gettera. – Jarod42

Odpowiedz

12

można funkcjonować podpis jest tuple< vector<int>, vector<int>, vector<int> >, który jest tymczasowy i elementy kwalifikują się do przeniesienia, więc

std::tie(fact, mean, err) = getAllBlockMeanErrorTuple(vec) 

powinien poruszać przypisać fact, mean i err.

Oto przykładowy program, aby zobaczyć na własne oczy (demo):

#include <iostream> 
#include <vector> 
#include <tuple> 

struct A 
{ 
    A() = default; 
    ~A() = default; 
    A(const A&) 
    { 
     std::cout << "Copy ctor\n"; 
    } 
    A(A&&) 
    { 
     std::cout << "Move ctor\n"; 
    } 
    A& operator=(const A&) 
    { 
     std::cout << "Copy assign\n"; 
     return *this; 
    } 
    A& operator=(A&&) 
    { 
     std::cout << "Move assign\n"; 
     return *this; 
    } 
}; 

std::tuple<A, A> DoTheThing() 
{ 
    A first; 
    A second; 
    return std::make_tuple(first, second); 
} 

int main() 
{ 
    A first; 
    A second; 
    std::tie(first, second) = DoTheThing(); 
} 

wyjściowa:

Kopiowanie konstruktor
Kopiowanie konstruktor
Move przypisać
Move przypisać

Należy pamiętać, że funkcja musiała utworzyć kopie wektorów do zwrotu tuple, które mogą nie być tym, czego potrzebujesz. Możesz std::move elementy do std::make_tuple:

return make_tuple(std::move(fact), std::move(mean), std::move(err)); 

Here's the same example as above, but with std::move used in make_tuple

Należy zauważyć, że z C++ 17 za Wiązania strukturyzowane, można zapomnieć o używaniu std::tie w ogóle, i pochylić się bardziej na auto (dzięki @ Yakk):

auto[fact, mean, err] = getAllBlockMeanErrorTuple(vec); 

Pierwsze implementacje standardu C++ 17 dla brzękiem (3.8.0) i gcc (6.1.0) nie obsługują go jeszcze, ale wydaje się, że jest pewne wsparcie w C lang 4.0.0: Demo (Dzięki, @Revolver_Ocelot)

Zauważysz, że wyjście z strukturyzowanych wiązań zmian:

Move konstruktor
Move konstruktor

wskazujące, że skorzystaj z funkcji copy-elision, która oszczędza dodatkowe operacje przenoszenia.

+1

'auto [fact, mean, err] = getAllBlockMeanErrorTuple (vec);' – Yakk

+1

@Yakk: Czy to nie C++ 17? – AndyG

+0

Tak, ale chciałbym powiedzieć, że warto wspomnieć, przynajmniej na marginesie. – Yakk

11
std::tie(fact, mean, err) = getAllBlockMeanErrorTuple(vec); 

wykonałaby przeniesienie zadania.

Ale jak wspomniano w komentarzu

return make_tuple(fact, mean, err); 

zrobi kopię, można rozwiązać ten z:

return make_tuple(std::move(fact), std::move(mean), std::move(err)); 
+0

Przynajmniej wspomnij o strukturalnych wiązaniach C++ 17! Jesteśmy zaledwie miesiąc od tego, że tu jest! (dla ograniczonych wartości tutaj) – Yakk

+0

Dziękuję Jarod42. –