Let's I have
struct Vector {
float i,j,k;
}
I want to zero all elements of vec declared below (i,j,k=0)
std::vector <Vector> vec;
vec.resize(num,0);
I don't want to use reserve() and then push_back() zeroes one by one.
Another thing is, after succesfully initializing vec, I want to set all members of vec to zero again after it is manipulated. Is there something like memset for vectors?
EDIT:
I compared all of the methods in Mike Seymour's and Xeo's answers and as a result
size_t size = vec.size();
vec.clear();
vec.resize(size); is the fastest if they are repeated frequently in a loop.
That's very simple:
vec.resize(num);
or initialise it with the required size:
std::vector<Vector> vec(num);
Both the constructor and resize will fill new elements with value-initialised objects. A value-initialised object of a type with no default constructor (such as your Vector) will have all numeric members initialised to zero.
To reset everything to zero, either
size_t size = vec.size();
vec.clear();
vec.resize(size);
or:
std::fill(vec.begin(), vec.end(), Vector());
or, less efficiently but with a strong exception guarantee:
std::vector<Vector>(vec.size()).swap(vec);
C++ way of setting all current elements to 0:
std::fill( vec.begin(), vec.end(), 0 );
Or, alternatively, to re-initialize to a given size:
vec.clear();
vec.resize(num, 0);
This might not be as performant as memset, but good enough for 99% of the cases.
You can just use memset, so long your Vector is a POD type:
std::vector<Vector> v(num, 0); // inital fill
// do stuff
memset(&v[0], 0, sizeof(Vector) * v.size());
Though the C++ version would be with std::fill
#include <algorithm>
std::fill(v.begin(), v.end(), 0);
Related
Is it possible to create a std::vector<T*> vec; during initialization, such that each element of vec stores a distinct address on the heap?
Simply doing
int N = 10;
std::vector<T*> vec(N, new T)
makes all elements of vec store the same address on the heap. Of course, I could simply just do
int N = 10;
std::vector<T*> vec(N);
std::for_each(vec.begin(), vec.end(), [](auto &ptr){
ptr = new int;
});
Is there any way to do it from within the constructor call?
Constructors that fill values into the vector all create duplicates of a single value, so they wont work in this case.
You can do a little better than std::for_each though. Since you want each element in the vector filled in with the result of a function, std::generate (or std::generate_n) is clearly a better fit:
std::vector<T *> vec(N);
std::generate(vec.begin(), vec.end(), [] { return new int; });
That said, a vector of raw pointers is most likely a mistake, so I'd recommend exploring other options.
If I wanted to copy the same value across an iterator range, I would think that it would be easy to have a noop iterator where you pass it a value, and when it is incremented, it would not move anywhere. This would allow using the existing std::copy and std::copy_if algorithms.
However, I can't seem to find such a beast. Am I going to have to roll my own?
Use std::fill or std::fill_n algorithm.
Some containers, e.g. std::vector<> and std::list<>, have a constructor with size and initializer:
std::vector<int> v(10, 42); // 42 is the initializer
v.resize(20, 42); // Initialize new elements with 42.
As far as I know there is no iterator for this but there is an algorithm. std::generate will take a range an assign a value to each element that is returned from the generator passed to it. If you want to assign everything 42 for instance that would look like
std::vector<int> vec(20);
std::generate(vec.begin(), vec.end(), []() { return 42; });
You can even get values that change like
std::vector<int> vec(20);
std::generate(vec.begin(), vec.end(), []() { static int counter = 0; ++counter; return counter * counter; });
is there any quick way to make all elements of a 2D vector zero? I have the following:
`typedef class Chrom
{
vector<vector <short int>> bit;
vector<vector <float>> t1; //this is wij in the model
}
chrome ProblemConstraint;
And after resizing I make t1 as t1[Machines][Jobs]. I wonder is there any quick way that I set all elements of t1 to zero? I know there is fill but when I write
fill(ProblemConstraint.t1[0], ProblemConstraint.t1[0]+Jobs*Machines, 0);
I get error. Any help is appreciated.
As #UnholySheep commented, std::fill accepts the pair of the iterators you need to pass, not the pointer to the elements:
std::fill(ProblemConstraint.t1[0].begin(), ProblemConstraint.t1[0].end(), 0);
However, you can also initialize the values during resizing the vectors, as std::vector::resize has an overload with the element's default value:
void resize( size_type count, const value_type& value );
So, you could do:
t1[0].resize(Jobs, 0);
at the resize point.
I want to know what are difference(s) between vector's push_back and insert functions.
Is there a structural difference(s)?
Is there a really big performance difference(s)?
The biggest difference is their functionality. push_back always puts a new element at the end of the vector and insert allows you to select new element's position. This impacts the performance. vector elements are moved in the memory only when it's necessary to increase it's length because too little memory was allocated for it. On the other hand insert forces to move all elements after the selected position of a new element. You simply have to make a place for it. This is why insert might often be less efficient than push_back.
The functions have different purposes. vector::insert allows you to insert an object at a specified position in the vector, whereas vector::push_back will just stick the object on the end. See the following example:
using namespace std;
vector<int> v = {1, 3, 4};
v.insert(next(begin(v)), 2);
v.push_back(5);
// v now contains {1, 2, 3, 4, 5}
You can use insert to perform the same job as push_back with v.insert(v.end(), value).
Beside the fact, that push_back(x) does the same as insert(x, end()) (maybe with slightly better performance), there are several important thing to know about these functions:
push_back exists only on BackInsertionSequence containers - so, for example, it doesn't exist on set. It couldn't because push_back() grants you that it will always add at the end.
Some containers can also satisfy FrontInsertionSequence and they have push_front. This is satisfied by deque, but not by vector.
The insert(x, ITERATOR) is from InsertionSequence, which is common for set and vector. This way you can use either set or vector as a target for multiple insertions. However, set has additionally insert(x), which does practically the same thing (this first insert in set means only to speed up searching for appropriate place by starting from a different iterator - a feature not used in this case).
Note about the last case that if you are going to add elements in the loop, then doing container.push_back(x) and container.insert(x, container.end()) will do effectively the same thing. However this won't be true if you get this container.end() first and then use it in the whole loop.
For example, you could risk the following code:
auto pe = v.end();
for (auto& s: a)
v.insert(s, pe);
This will effectively copy whole a into v vector, in reverse order, and only if you are lucky enough to not get the vector reallocated for extension (you can prevent this by calling reserve() first); if you are not so lucky, you'll get so-called UndefinedBehavior(tm). Theoretically this isn't allowed because vector's iterators are considered invalidated every time a new element is added.
If you do it this way:
copy(a.begin(), a.end(), back_inserter(v);
it will copy a at the end of v in the original order, and this doesn't carry a risk of iterator invalidation.
[EDIT] I made previously this code look this way, and it was a mistake because inserter actually maintains the validity and advancement of the iterator:
copy(a.begin(), a.end(), inserter(v, v.end());
So this code will also add all elements in the original order without any risk.
I didn't see it in any of the comments above but it is important to know:
If we wish to add a new element to a given vector and the new size of the vector (including the new element) surpasses the current vector capacity it will cause an automatic reallocation of the allocated storage space.
And Beacuse memory allocation is an action we wish to minimize it will increase the capacity both in push_back and insert in the same way (for a vector with n elemeny will add about n/2).
So in terms of memory efficiency it is safe to say, use what ever you like best.
for example:
std::vector<int> test_Insert = { 1,2,3,4,5,6,7 };
std::vector<int> test_Push_Back = { 1,2,3,4,5,6,7 };
std::cout << test_Insert.capacity() << std::endl;
std::cout << test_Push_Back.capacity() << std::endl;
test_Insert.push_back(8);
test_Push_Back.insert(test_Push_Back.end(), 8);
std::cout << test_Insert.capacity() << std::endl;
std::cout << test_Push_Back.capacity() << std::endl;
This code will print:
7
7
10
10
Since there's no actual performance data, I reluctantly wrote some code to produce it. Keep in mind that I wrote this code because I wondered "Should I push_back multiple single elements, or use insert?".
#include <iostream>
#include <vector>
#include <cassert>
#include <chrono>
using namespace std;
vector<float> pushBackTest()
{
vector<float> v;
for(int i =0;i<10000000;i++)
{
// Using a for-loop took 200ms more (in the output)
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
v.push_back(7);
v.push_back(8);
v.push_back(9);
}
return v;
}
vector<float> insertTest()
{
vector<float> v;
for(int i =0;i<10000000;i++)
{
v.insert(v.end(), {0,1,2,3,4,5,6,7,8,9});
}
return v;
}
int main()
{
std::chrono::steady_clock::time_point start = chrono::steady_clock::now();
vector<float> a = pushBackTest();
cout<<"pushBackTest: "<<chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start).count()<<"ms"<<endl;
start = std::chrono::steady_clock::now();
vector<float> b = insertTest();
cout<<"insertTest: "<<chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start).count()<<"ms"<<endl;
assert(a==b);
return 0;
}
Output:
pushBackTest: 5544ms
insertTest: 3402ms
Since curiosity killed my time, I run a similar test but adding a single number instead of multiple ones.
So, the two new functions are:
vector<float> pushBackTest()
{
vector<float> v;
for(int i =0;i<10000000;i++)
{
v.push_back(1);
}
return v;
}
vector<float> insertTest()
{
vector<float> v;
for(int i =0;i<10000000;i++)
{
v.insert(v.end(), 1);
}
return v;
}
Output:
pushBackTest: 452ms
insertTest: 615ms
So, if you wanna add batch of elements, insert is faster, otherwise push_back it is. Also, keep in mind that push_back can only push... back, yeah.
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 :)
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());
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...
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());
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.