Reputation: 13222
If I reserve some space for a vector, and then I copy some values in it with std::copy_n()
, I get the values copied correctly and accessible, but the size of the vector is still zero. Is this the expected behaviour? Should I resize the vector instead, even if it is not as efficient?
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<double> src, dest;
for(double x = 0.0; x < 100.0; ++x)
src.push_back(x);
dest.reserve(src.size());
std::copy_n(src.cbegin(), src.size(), dest.begin());
std::cout << "src.size() = " << src.size() << std::endl;
std::cout << "dest.size() = " << dest.size() << std::endl;
for(size_t i = 0; i < src.size(); ++i)
std::cout << dest[i] << " ";
}
Compilers tested: clang, gcc, Visual C++
Upvotes: 6
Views: 2115
Reputation: 76523
The key thing to remember about standard library algorithms is that they operate on ranges, not containers. Containers are one of the ways that you can create ranges, but they are not the only way. Algorithms that write results into a range assume that they are writing to valid locations; they do not, and cannot, extend the range that they are writing to.
So when you call std::copy_n
you must provide a range that's large enough to hold the result. That means setting up the range with dest.resize(src.size());
, not just allocating memory with dest.reserve(std.size());
.
Alternatively, you can provide a range that knows that it's attached to a container and needs to adjust the size, by calling the algorithm with std::back_inserter(dest)
instead of dest.begin()
.
Upvotes: 3
Reputation: 173044
but the size of the vector is still zero
std::copy_n
won't change the size of the container, just copy the value and step the iterators; it even doesn't have any information about the container. So the code has undefined behavior, even it seems to work fine.
Should I resize the vector instead, even if it is not as efficient?
Yes you could use std::vector::resize
instead of std::vector::reserve
to solve the issue. As you might have thought, it means all the elements will be constructed by resize
firstly, then assigned by copy_n
.
You could use std::back_inserter, which will append elements at the end of the container by invoking the container's push_back()
member function (i.e. construct elements directly), thus increase the container's size. e.g.
dest.reserve(src.size());
std::copy_n(src.cbegin(), src.size(), std::back_inserter(dest));
Upvotes: 8
Reputation: 706
Your dest
allocated memory to store elements after you called reserve
, but it doesn't call constructors and it is actually empty, so your code leads to UB. Use resize
to actually create those elements and then it will be ok.
dest.resize(src.size());
std::copy_n(src.cbegin(), src.size(), dest.begin());
std::cout << "src.size() = " << src.size() << std::endl;
std::cout << "dest.size() = " << dest.size() << std::endl;
for(size_t i = 0; i < src.size(); ++i)
std::cout << dest[i] << " ";
Upvotes: 0
Reputation: 873
A std::vector has a size and a capacity. It reserves some more space than necessary to make insertion faster. reserve enables you to specifiy that capacity, while resize changes the real size of the vector.
Upvotes: 1