#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> a{ 1, 2, 3 };
copy(a.begin(), a.end(), back_inserter(a));
for (const int& x : a)
cout << x << ' ';
}
Output:
1 2 3 1 -572662307 -572662307
Expected output:
1 2 3 1 2 3
I have no idea why is this happening. What's is the reason for this behavior?
The standard algorithm for copying is std::copy . We can use it for copying elements from the source vector to the destination vector.
Begin Initialize a vector v1 with its elements. Declare another vector v2 and copying elements of first vector to second vector using constructor method and they are deeply copied. Print the elements of v1. Print the elements of v2.
std::copy. Copies the elements in the range [first,last) into the range beginning at result . The function returns an iterator to the end of the destination range (which points to the element following the last element copied).
1) std::vector is a sequence container that encapsulates dynamic size arrays. 2) std::pmr::vector is an alias template that uses a polymorphic allocator. The elements are stored contiguously, which means that elements can be accessed not only through iterators, but also using offsets to regular pointers to elements.
The problem is that as the vector grows, iterators you provided are potentially invalidated. You can fix that by using reserve
. It is, in general, a good idea to use reserve
if you know the size in advance so there are fewer allocations going on:
#include <algorithm>
#include <vector>
int main() {
std::vector<int> a{1, 2, 3};
a.reserve(a.size() * 2);
a.insert(a.end(), a.begin(), a.end());
}
Do note that insert
is often better and simpler than back_inserter
.
In general your program has undefined behavior because the iterators can become invalid during adding new elements to the vector.
You have to reserve enough memory in the vector. For example
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<int> v = { 1, 2, 3 };
v.reserve( 2 * v.size() );
std::copy( std::begin( v ), std::end( v ), std::back_inserter( v ) );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
If your compiler supports the C++ 17 Standard (in the C++ 14 Standard there is a requirement that the iterators that specify the copied range were not iterators of the vector itself) then you may use the method insert, For example
#include <iostream>
#include <vector>
#include <iterator>
int main()
{
std::vector<int> v = { 1, 2, 3 };
v.insert( std::end( v ), std::begin( v ), std::end( v ) );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
Possible implementation of copy
from cppreference:
template<class InputIt, class OutputIt> OutputIt copy(InputIt first, InputIt last, OutputIt d_first) { while (first != last) { *d_first++ = *first++; } return d_first; }
With a back_inserter
*first++
will call push_back
on the vector. Calling push_back
potentially invalidates all iterators when the vector needs to reallocate. Hence your code has undefined behavior.
Note that back_inserter
is a little exotic. It violates the usual strict separation of iterators and container, because the iterator has to store a reference to the container. That alone does not explain the effect you see, but it is indication that one needs to be careful when the iterator actually does modify the container.
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