Concatenating two std::vectors

512,664

Solution 1

vector1.insert( vector1.end(), vector2.begin(), vector2.end() );

Solution 2

If you are using C++11, and wish to move the elements rather than merely copying them, you can use std::move_iterator along with insert (or copy):

#include <vector>
#include <iostream>
#include <iterator>

int main(int argc, char** argv) {
  std::vector<int> dest{1,2,3,4,5};
  std::vector<int> src{6,7,8,9,10};

  // Move elements from src to dest.
  // src is left in undefined but safe-to-destruct state.
  dest.insert(
      dest.end(),
      std::make_move_iterator(src.begin()),
      std::make_move_iterator(src.end())
    );

  // Print out concatenated vector.
  std::copy(
      dest.begin(),
      dest.end(),
      std::ostream_iterator<int>(std::cout, "\n")
    );

  return 0;
}

This will not be more efficient for the example with ints, since moving them is no more efficient than copying them, but for a data structure with optimized moves, it can avoid copying unnecessary state:

#include <vector>
#include <iostream>
#include <iterator>

int main(int argc, char** argv) {
  std::vector<std::vector<int>> dest{{1,2,3,4,5}, {3,4}};
  std::vector<std::vector<int>> src{{6,7,8,9,10}};

  // Move elements from src to dest.
  // src is left in undefined but safe-to-destruct state.
  dest.insert(
      dest.end(),
      std::make_move_iterator(src.begin()),
      std::make_move_iterator(src.end())
    );

  return 0;
}

After the move, src's element is left in an undefined but safe-to-destruct state, and its former elements were transfered directly to dest's new element at the end.

Solution 3

I would use the insert function, something like:

vector<int> a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());

Solution 4

Or you could use:

std::copy(source.begin(), source.end(), std::back_inserter(destination));

This pattern is useful if the two vectors don't contain exactly the same type of thing, because you can use something instead of std::back_inserter to convert from one type to the other.

Solution 5

With C++11, I'd prefer following to append vector b to a:

std::move(b.begin(), b.end(), std::back_inserter(a));

when a and b are not overlapped, and b is not going to be used anymore.


This is std::move from <algorithm>, not the usual std::move from <utility>.

Share:
512,664
Admin
Author by

Admin

Updated on July 08, 2022

Comments

  • Admin
    Admin almost 2 years

    How do I concatenate two std::vectors?

  • Joe Pineda
    Joe Pineda over 15 years
    I'd only add code to first get the number of elements each vector holds, and set vector1 to be the one holding the greatest. Should you do otherwise you're doing a lot of unnecessary copying.
  • Yogesh Arora
    Yogesh Arora about 14 years
    the copy method is a not such a good way. It will call push_back multiple time which means that if a lot of elements have to be inserted this could mean multiple reallocations. it is better to use insert as the vector implementation could do some optimization to avoid reallocations. it could reserve memory before starting copying
  • Roger Lipscombe
    Roger Lipscombe about 14 years
    @Yogesh: granted, but there's nothing stopping you calling reserve first. The reason std::copy is sometimes useful is if you want to use something other than back_inserter.
  • Alexander Rafferty
    Alexander Rafferty almost 13 years
    I have a question. Will this work if vector1 and vector2 are the same vectors?
  • Faheem Mitha
    Faheem Mitha about 12 years
    If you have concatenating several vectors to one, is it helpful to call reserve on the destination vector first?
  • Drew Dormann
    Drew Dormann almost 12 years
    @AlexanderRafferty: Only if vector1.capacity() >= 2 * vector1.size(). Which is atypical unless you've called std::vector::reserve(). Otherwise the vector will reallocate, invalidating the iterators passed as parameters 2 and 3.
  • Aidin
    Aidin about 10 years
    @FaheemMitha: Since arguments of insert are vectors, it's already know how many elements are ahead and will handle it itself. If we were inserting other things like array, it was useful to reserve the space first.
  • Faheem Mitha
    Faheem Mitha about 10 years
    @Aidin I see. Thanks for the clarification.
  • Knitschi
    Knitschi over 9 years
    The std::make_move_iterator() method helped me when trying to concatenate std::vectors of std::unique_ptr.
  • Class Skeleton
    Class Skeleton over 8 years
    Is it not possible for v1.erase(... to throw too?
  • Martin Bonner supports Monica
    Martin Bonner supports Monica over 8 years
    Undefined behaviour if a actually is b (which is OK if you know that can never happen - but worth being aware of in general purpose code).
  • Martin Bonner supports Monica
    Martin Bonner supports Monica over 8 years
    When you say "multiple allocations", that is true - but the number of allocations is at worst log(number of entries added) - which means that the cost of adding an entry is constant in the number of entries added. (Basically, don't worry about it unless profiling shows you need a reserve).
  • Deqing
    Deqing about 8 years
    @MartinBonner Thanks for mentioning that. Probably I should turn back to the old insert way which is safer.
  • Martin Broadhurst
    Martin Broadhurst about 8 years
    You might want to use std::transform to do this instead.
  • Mooing Duck
    Mooing Duck about 8 years
    @Khaur: That's horrifying to the point it's hard to believe. It's super trivial for an implementation to detect the iterators are random access, calculate the size, and pre-reserve the needed space. I think MSFT's even does that for forward iterators.
  • Khaur
    Khaur about 8 years
    @MooingDuck You're right, I missed the dispatcher and thought the input iterator version applied for all types of iterators. The forward iterator version does a lot more stuff. Thanks for pointing it out, I deleted my initial comment so that it doesn't show up without yours.
  • leeor_net
    leeor_net almost 8 years
    Don't know why this was down-voted. It may not be the most efficient way of doing this but it's not wrong and is effective.
  • Manohar Reddy Poreddy
    Manohar Reddy Poreddy over 7 years
    just add following header line the begin: #include <iterator>
  • xaxxon
    xaxxon over 7 years
    Ah, the OTHER std::move. Quite confusing the first time you see it.
  • Asu
    Asu over 7 years
    std:: is deduced through argument-dependent lookup. end(a) will be enough.
  • nmr
    nmr over 7 years
    It's too bad there isn't a more succinct expression in the standard library. .concat or += or something
  • Scott Weldon
    Scott Weldon over 7 years
    While this code snippet may solve the problem, it doesn't explain why or how it answers the question. Please include an explanation for your code, as that really helps to improve the quality of your post. Flaggers / reviewers: For code-only answers such as this one, downvote, don't delete! (Note: This answer may actually be simple enough to make an explanation, and thus downvotes, unnecessary. You may still want to add an explanation to prevent more NAA/VLQ flags.)
  • Mat
    Mat over 7 years
    What does your answer add that hasn't already been provided in other answers?
  • Potatoswatter
    Potatoswatter over 7 years
    @Asu ADL will only add std:: if the type of a comes from std, which defeats the generic aspect.
  • Potatoswatter
    Potatoswatter over 7 years
    insert already handles this. Also, this call to erase is equivalent to a resize.
  • Asu
    Asu over 7 years
    good point. in this case it's a vector so it would work anyways, but yes that's a better solution.
  • marcv81
    marcv81 about 7 years
    @Mat: Bold characters.
  • tmlen
    tmlen about 6 years
    If the original vector(s) are no longer needed after, it may be better to use std::move_iterator so that elements are moved instead of copied. (see en.cppreference.com/w/cpp/iterator/move_iterator).
  • Denis Yaroshevskiy
    Denis Yaroshevskiy over 5 years
    copy sucks a lot, even with reserve. vector::insert will avoid all the checks: quick-bench.com/bLJO4OfkAzMcWia7Pa80ynwmAIA
  • James Curran
    James Curran over 5 years
    std::begin()/end() were added for collections (like arrays) which don't have them as member functions. But arrays also don't have an insert() member function, and calls the question "Is there a collection with an insert() but without begin() (which works with the std::begin()) ?"
  • GPhilo
    GPhilo over 5 years
    Is this different from insert() with move_iterators? If so, how?
  • YSC
    YSC over 5 years
    @nmr In C++, this is quite succinct.
  • YSC
    YSC over 5 years
    I've added a note about what std::move we are talking here, since most people don't know this overload. Hope it's an improvement.
  • Zimano
    Zimano about 5 years
    So simple, yet I never thought about it that way!
  • L. F.
    L. F. about 5 years
    What is setcapacity? What is function: ?
  • David Stone
    David Stone almost 5 years
    The sample code is incorrect. v1.insert(v2.end()... is using an iterator into v2 to specify the position in v1.
  • j00hi
    j00hi over 4 years
    It's hard to get an overview of all the different answers to this question. The std::vector::insert approach has been posted in several other answers as well, but this one has most upvotes, so I'll ask/state here: Using insert should have an advantage over other approaches which use back_inserter because insert could potentially memcpy in one bulk while the approaches that use back_inserter must iterate over the vector to be inserted element by element. Do I see this right?
  • j b
    j b over 4 years
    I don't think it's any easier to use than std::vector::insert, but it does to something different: merging two ranges into a new range vs inserting one vector at the end of another. Worth mentioning in the answer?
  • qwr
    qwr over 4 years
    You can also use a quick swap. @DavidStone I edited it so that the concat order may be changed. Is it possible to add to the beginning of a vector?
  • David Stone
    David Stone over 4 years
    You can insert into the beginning, but that will be slower. To truly "concatenate", however, the order typically does matter, so that is what you need to do.
  • Matthieu H
    Matthieu H over 4 years
    UsingT operator+(const T & a, const T & b) is dangerous, it is better to use vector<T> operator+(const vector<T> & a, const vector<T> & b).
  • Matthieu H
    Matthieu H over 4 years
    @L.F. I think he's talking about the resize method.
  • IgNite
    IgNite about 4 years
    Isn't this the same with the answer given by Tom Ritter and Robert Gamble in 2008?
  • kshenoy
    kshenoy about 4 years
    What's the difference between this and std::move(src.begin(), src.end(), back_inserter(dest))?
  • Tarick Welling
    Tarick Welling almost 4 years
    besides it not working, this code is heavily non-idiomatic. You should at least be using auto iterators instead of manual indexing. You don't care about what index you are concatenating only that it is done sequentially.
  • wcochran
    wcochran over 3 years
    I predict this will be the appropriate answer in 2023 or so.
  • Jerry Jeremiah
    Jerry Jeremiah over 3 years
    @Deqing I'm not sure insert is better... If a is b then as soon as you insert a few elements it will reallocate and invalidate the iterators passed to insert which will then continue to be used, right?
  • Jerry Jeremiah
    Jerry Jeremiah over 3 years
    And it works if you pass the same vector in as both parameters to concatenate a vector with itself.
  • Ido Kessler
    Ido Kessler over 3 years
    you should prefer not to use reserve, as it might come with a massive overhead. Look here: stackoverflow.com/a/64102335/7110367
  • Admin
    Admin over 3 years
    I don't like this answer because you don't insert v2 after v1 in all case (without specifying it with a note). Otherwise, your answer could be more complete if you add a solution which save the concatenation in another vector rather than modifiying one of them.
  • Admin
    Admin over 3 years
    @TarickWelling I don't see why you said this code is not working, could you be more specific ?
  • Admin
    Admin over 3 years
    Your description is not clear (and useless, sorry). Otherwise, your answer could be more complete if you add a second solution which save the concatenation in another vector rather than modifiying one of them.
  • Tarick Welling
    Tarick Welling over 3 years
    Did you check the date of my comment? You fixed the bugs in your code now it is just not idiomatic.
  • yrHeTateJlb
    yrHeTateJlb over 3 years
    @kshenoy, insert might allocate necessary amount of memory in one turn. When back_inserter might lead to several reallocations
  • Pavan Chandaka
    Pavan Chandaka over 3 years
    Ok. I understood what is expected in the answer. I will add.
  • Samuel Li
    Samuel Li over 3 years
    @DenisYaroshevskiy That's a striking difference in performance. Any idea why is that happening? Conceptually, the using_resize method writes the memory space of res twice, should be the slower one ??
  • Denis Yaroshevskiy
    Denis Yaroshevskiy over 3 years
    @SamuelLi - mostly the if > capacity_ in push_back if a problem. It's a problem enough that the memset in resize does not matter.
  • Yakk - Adam Nevraumont
    Yakk - Adam Nevraumont almost 3 years
    @leeo non const ref args for one
  • Yakk - Adam Nevraumont
    Yakk - Adam Nevraumont almost 3 years
    Have 1st call 2nd overload
  • Sergey Kolesnik
    Sergey Kolesnik about 2 years
    this can be very confusing and is not recommended. += might be perceived as a modification element-wise.
  • Human-Compiler
    Human-Compiler almost 2 years
    This isn't a good idea because the operator won't be found by ADL, since both arguments are from namespace std. This means either the symbols have to be defined/pulled into the global namespace to be discovered, or in the same namespace as any code using it. Not really ideal over just a named function that doesn't have any of these issues.