This question already has an answer here:
-
Nice way to append a vector to itself
4 answers
I am trying to make a copy of a vector of string and append it to the end of its original vector, i.e. duplicating its contents. Example:
Input : vector<string> s = {"abc", "def"}
Output: vector<string> s = {"abc", "def", "abc", "def"}
I was using the insert method, i.e.
s.insert(s.end(), s.begin(), s.end());
However, this exhibits compiler-dependent results. In, LLVM clang, it gave me the expected answer.
With GCC it gave me
Output: vector<string> s = {"abc", "def", "", ""}
I am wondering why this happens and what's the safest way to achieve this vector duplication goal?
Here is the ideone.com link for the program above: http://ideone.com/40CH8q
Although it can possibly be done with iterators, a safe alternative is to avoid them:
size_t size = v.size(); // Of course we shouldn't access .size() in the loop...
v.reserve(size * 2); // Preallocation. Thanks @Ali for this performance hint
for (size_t i = 0; i < size; ++i)
v.push_back(v[i]);
In general, working with iterators while also modifying the data structure (not only its elements) is dangerous; you should read carefully when iterators are invalidated and when it's safe to reuse old iterators after a modification. Thus, it sometimes makes sense to use the "old" method to iterate through a random-access sequence: using an index variable.
As others have already pointed out, you need to make sure by calling vector::reserve()
that the vector doesn't get reallocated during insertion. (It is also a good idea to call reserve if you chose to put the elements with push_back()
into your vector.)
Then there is still the iterator invalidation issue (as detailed under vector::insert()
) but the code below, as far as I know, bypasses that:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
using namespace std;
int main() {
vector<string> s{"abc", "def"};
auto size = s.size();
s.reserve(2*size); // <-- This one is essential to ensure
// no reallocation during insertion
const string* first = s.data(); // using pointer, instead of iterator
copy(first, first+size, back_inserter(s));
for (const auto& e : s)
cout << e << '\t';
cout << endl;
}
As already stated, it seems all you need to do is make a call to reserve
:
sv.reserve(sv.size() * 2);
This is because if a reallocation occurs, the iterators are invalidated. You can check this for yourself:
std::cout << sv.capacity() << "\n"; // 2
The new size will be bigger than the capacity so a reallocation occurs.
This can be done this way too
vector<string> data = {"abc", "def"}; // Input String Vector
int len = data.size();
for(int i = 0; i < len; i++)
{
data.push_back(data[i]); // Making Copy of String Vector
}
vector<string> data = {"abc", "def", "abc", "def"};
//Resultant String Vector