2013-06-09 6 views

risposta

27

Basta fare:

#include <iterator> 
#include <algorithm> 

// ... 

void MoveAppend(std::vector<X>& src, std::vector<X>& dst) 
{ 
    if (dst.empty()) 
    { 
     dst = std::move(src); 
    } 
    else 
    { 
     dst.reserve(dst.size() + src.size()); 
     std::move(std::begin(src), std::end(src), std::back_inserter(dst)); 
     src.clear(); 
    } 
} 

Se dst è vuota, una mossa assegnazione src-dst farà il lavoro - che sarà a buon mercato come può essere, solo "rubare" la matrice incapsulata dain modo che in seguito sia indicato da dst.

Se dst non è vuoto, gli elementi aggiunti a dst verranno spostati dagli elementi di src. Dopo la chiamata a std::move(), src non sarà vuoto: conterrà gli elementi spostati da "zombie". Ecco perché la chiamata a clear() è ancora necessaria.

+1

DST non è vuoto. –

+0

@ ŁukaszLew: OK, questo cambia le cose. Modificherò –

+0

@ ŁukaszLew: ho cambiato la risposta. Scusa per l'incomprensione –

11

avrei un po 'preferisco questo alla risposta accettata:

#include <vector> 
#include <iterator> 
#include <utility> 

template <typename T> 
typename std::vector<T>::iterator append(const std::vector<T>& src, std::vector<T>& dest) 
{ 
    typename std::vector<T>::iterator result; 

    if (dest.empty()) { 
     dest = src; 
     result = std::begin(dest); 
    } else { 
     result = dest.insert(std::end(dest), std::cbegin(src), std::cend(src)); 
    } 

    return result; 
} 

template <typename T> 
typename std::vector<T>::iterator append(std::vector<T>&& src, std::vector<T>& dest) 
{ 
    typename std::vector<T>::iterator result; 

    if (dest.empty()) { 
     dest = std::move(src); 
     result = std::begin(dest); 
    } else { 
     result = dest.insert(std::end(dest), 
          std::make_move_iterator(std::begin(src)), 
          std::make_move_iterator(std::end(src))); 
    } 

    src.clear(); 
    src.shrink_to_fit(); 

    return result; 
} 

Esempio:

#include <string> 
#include <algorithm> 
#include <iostream> 

int main() 
{ 
    const std::vector<std::string> v1 {"world", "!"}; 

    std::vector<std::string> v2 {" "}, v3 {"hello"}, v4 {}; 

    append(v1, v2); // copies 
    append(std::move(v2), v3); // moves 
    append(std::move(v3), v4); // moves 

    std::copy(std::cbegin(v4), std::cend(v4), std::ostream_iterator<std::string> {std::cout}); 
    std::cout << std::endl; 
} 
+0

Penso che questa sia una risposta molto migliore, ha overload per lvalue e rvalue source, e usa std :: vector :: insert(). – dats

+2

Perché si "pulisce" la sorgente di valore? Penso che stia facendo un lavoro extra non richiesto – dats

+0

@dats È un punto interessante - la mia opinione è che il chiamante si aspetterebbe t La capacità della sorgente del valore di riferimento è zero dopo la chiamata, che altrimenti non sarebbe il caso. – Daniel

Problemi correlati