Reputation: 264
I want to use a factory function for my vector and also use the iterators without calling resize which blows my previous values ?
Is it possible or am I missing a point in STL design ?
#include <vector>
#include <algorithm>
#include <iostream>
struct A
{
A():_x(42){}
A(double x):_x(x){}
double _x;
};
struct factory
{
A operator()()
{
return A(3.14);
}
};
int main()
{
std::vector<A> v;
int nbr = 3;
v.reserve(nbr);
std::generate_n(v.begin(), nbr, factory());
std::cout << "Good values" << std::endl;
for(int i = 0 ; i < nbr ; ++i)
std::cout << v[i]._x << std::endl;
v.resize(nbr); //How I can have the syntax below without the resize which blows my previous values ?
std::cout << "resize has been called so values are bad (i.e default ctor)" << std::endl;
for(std::vector<A>::iterator it = v.begin() ; it != v.end() ; ++it)
std::cout << (*it)._x << std::endl;
}
Thanks :)
Upvotes: 0
Views: 581
Reputation: 320621
The first part of your code is already broken. In order to create vector elements you have to call resize
, not reserve
. reserve
can only reserve future vector capacity by allocating raw memory, but it does not create (construct) real vector elements. You are generally not allowed to access vector elements that reside between vector's size and vector's capacity.
You called reserve
and then you are tried to use your vector as if the elements have already been constructed: you assign values to them and you attempt to read and print these values. In general case this is illegal, it generally leads to undefined behavior. Meanwhile, the size of your vector remained 0
, which is what you tried to compensate for by that strange call to resize
later.
You need to call resize
at the very beginning. Create a vector with the proper number of elements right from the start. (This can also be done by passing the initial size to vector's constructor).
For example, just do
int nbr = 3;
std::vector<A> v(nbr);
std::generate_n(v.begin(), nbr, factory());
or
std::vector<A> v;
int nbr = 3;
v.resize(nbr);
std::generate_n(v.begin(), nbr, factory());
and you are done. Forget about reserve
- you don't need it in this case.
Upvotes: 0
Reputation: 208421
Either I did not quite understand your concern, or else you have been mislead. resize()
does not modify any of the existing elements in the container (other than those removed if you resize to a smaller size).
Now, your actual problem is that you have undefined behavior in your program. The vector has capacity() == nbr
but size() == 0
when you call generate_n
, and that is writting beyond the end of the container. There are two solutions for this, first you can resize before calling generate_n
:
std::vector<A> v;
int nbr = 3;
v.resize(nbr);
std::generate_n(v.begin(), nbr, factory());
Or else you can change the type of the iterator:
std::vector<A> v;
int nbr = 3;
v.reserve(nbr);
std::generate_n(std::back_inserter(v), nbr, factory());
Upvotes: 8
Reputation: 96281
Your generate_n
is not generating values into a vector properly. The size of the vector is 0 so while it may appear to work correctly, you're just getting luck when writing beyond the end of the vector. You really do need to use resize
or similar. Alternately (and possibly more performant) you can use a back_inserter
: std::generate_n(std::back_inserter(v), nbr, factory());
Upvotes: 0
Reputation: 55897
v.reserve(nbr);
std::generate_n(v.begin(), nbr, factory());
It`s error. Reserve != resize, reserve only allocate memory if we need it. Why you use resize for print vector? Resize is function that resize vector, begin/end are not dependent on resize...
Upvotes: 0