2013-06-09 6 views

Antwort

27

Just do:

#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(); 
    } 
} 

Wenn dst leer ist, ein Schritt-Zuordnung src-dst wird die Arbeit machen - das so billig sein wird, wie es sein kann, nur das Array „Stehlen“ eingekapselt src, damit dst danach darauf zeigen.

Wenn dst nicht leer ist, werden Elemente, die an dst angehängt sind, aus Elementen in src verschoben. Nach dem Anruf an std::move(), src wird nicht leer sein - es wird "Zombie" von Elementen verschoben enthalten. Deshalb ist der Ruf nach clear() immer noch notwendig.

+1

dst nicht leer ist. –

+0

@ ŁukaszLew: OK, das ändert die Dinge. Ich werde bearbeiten –

+0

@ ŁukaszLew: Ich habe die Antwort geändert. Entschuldigung für das Missverständnis –

11

Ich würde dies etwas lieber die akzeptierte Antwort:

#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; 
} 

Beispiel:

#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

Ich denke das ist eine viel bessere Antwort, hat Überladungen für lvalue und rvalue source, und verwendet std :: vector :: insert(). – dats

+2

Warum "reinigen" Sie die rvalue-Quelle? Ich denke, das ist unerbetene zusätzliche Arbeit. – dats

+0

@ dats Es ist ein interessanter Punkt - meiner Ansicht ist, dass der Anrufer t erwarten würde Die Kapazität der R-Quelle ist nach dem Aufruf Null, was sonst nicht der Fall wäre. – Daniel

Verwandte Themen