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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With