I am trying to figure out the best way of accessing a position in a vector using an iterator. I'm aware iterators behave like pointers, so this is the only method I came up with. I would like to know if there's a better or just a different way. Here's the code:
//This is a pointer to a vector of the class Particle BTW. vector < Particle > *particleList;
vector<Particle>::iterator it = particleList->begin();
// I assign a specific position outside the loop to a new iterator that won't be affected
vector<Particle>::iterator it2 = particleList->begin() + 3;
for( it; it != particleList->end(); it++){
it->draw();
//I'm interested in the velocity of this element in particular
cout << it2->vel << endl;
}
Thanks,
M
Try the following
for (auto i = particleList->begin(); i < particleList->begin(); ++i) {
i->draw();
std::cout << (i+3)->vel << "\n";
}
Note, there is no reason to use std::endl, std::endl has an implicit flush which lowers performance when outputting to say a log file, and when outputting to console it is already line buffered meaning that a line ending will already flush.
Note 2, you can only use + with i since i is a random access iterator because particleList is a std::vector, if you change say particleList to a std::list then the iterator will be a bidirectional iterator instead of a random access iterator and you will not be able to use + in that case you would need to use std::advance like WhozCraig mentioned, but do so on a copy like so:
for (auto i = particleList->begin(); i < particleList->begin(); ++i) {
i->draw();
auto i2 = i;
std::advance(i2, 3)
std::cout << i2->vel << "\n";
}
Though personally, in this case I would just iterate with two iterators instead of std::advance since std::advance is linear in time. Do something like:
auto i = particleList->begin();
auto i2 = particleList->begin();
std::advance(i2, 3);
for (; i < particleList->end(); ++i, ++i2) {
i->draw();
std::cout << i2->vel << "\n";
}
Note 3: (i+3) and i2 will run off the end of your list (vector), so do something smart there.
Related
These two example both work and do the same thing.
I'm just trying to get what is the difference between them in terms of optimization, speed and overall. Which approach is better and why? Thanks in advance.
First example:
std::map<std::vector<int>, std::vector<double>> data
printMap(&data);
...
void printMap(std::map<std::vector<int>, std::vector<double>> *p_data){
for(std::map<std::vector<int>, std::vector<double>>::iterator itr = p_data->begin(); itr != p_data->end(); ++itr){
for(auto it = itr->first.begin(); it != itr->first.end(); ++it){
std::cout << *it << std::endl;
}
for(auto it2 = itr->second.begin(); it2 != itr->second.end(); ++it2){
std::cout << *it2 << std::endl;
}
}
}
Second example:
std::map<std::vector<int>, std::vector<double>> data;
printMapRef(data);
void printMapRef(std::map<std::vector<int>,std::vector<double>> &data){
for(std::map<std::vector<int>, std::vector<double>>::iterator itr = data.begin(); itr != data.end(); ++itr){
std::vector<int> tempVecInt = (*itr).first;
std::vector<double> tempVecDouble = (*itr).second;
for (int i = 0; i < tempVecInt.size(); i++){
std::cout << tempVecInt.at(i) << " ";
}
for (int j = 0; j < tempVecDouble.size(); j++){
std::cout << tempVecDouble.at(j) << " ";
}
}
}
The obvious difference is that the first iterates through the vectors that are in the map, while the second creates copies of the vectors in the map, then iterates through the copies.
The second also uses .at to index into each vector, which checks that the index is within bounds (and throws an exception if it isn't).
Especially if the vectors are large, those could easily make the second significantly slower than the first.
Most of the other differences are mostly syntactic. Personally I don't particularly like the syntax of the iterator-based loop, but iterators vs. indices is unlikely to make any real difference in speed or anything like that.
For what little it's worth, my own preference would be to pass the map in by (const) reference and use range-based for loops. I'd also at least consider using a function to print out the contents of each vector, since you have two loops that should be essentially identical.
I'm trying to learn C++ vectors.. Here is the code:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector <int> vec;
for(int i=0; i<=10; i++){
vec.push_back(i);
}
for(auto i=vec.begin(); i!=vec.end();i++){
cout<<*i<<" ";
}
}
Can anybody tell me what this part is?
for(auto i=vec.begin(); i!=vec.end();i++){
cout<<*i<<" ";
}
I've searched the Internet but couldn't find a clear explanation.
Ok, it prints the numbers that we put it in the vector, but can I get a more technical explanation?
for(auto i=vec.begin(); i!=vec.end();i++){
cout<<*i<<" ";
}
This is just the iterators in C++.
begin() function is used to return an iterator pointing to the first element of the vector.
Similarly, end() function is used to return an iterator pointing past the last element of the vector.
auto just deduces the type of the variable i. You could have also specified it as std::vector<int>::iterator i = vec.begin() . That's the type of the iterator you are using to loop over the vector.
In the above piece of code, you are basically iterating from the beginning of the vector until the end of the vector.
Inside the loop, you are just dereferencing the iterator and printing the value at the current position where the iterator is.
What the above piece of code is doing is basically the same as the following type of loop, which uses indexing to loop over the array:
for(size_t i = 0; i != vec.size() ; i++){
cout << vec[i] << " ";
}
You should read more about iterators, as they are a core concept in C++. You can read more about them here:
iterators
std::vector.begin()
std::vector.end()
This is an iterator to the first element in the vector: vec.begin()
An iterator to one-past the last element of the vector: vec.end()
auto deduces the type of i from vec.begin(), its an iterator. We really do not need to care about the exact type.
We only need to know that we can increment it: i++.
And compare two iterators with each other to check if we are at the end: i != vec.end().
And we can derference iterators to get the element the "point to": *i.
Without iterators the loop could be written as:
for (size_t i=0; i<vec.size(); ++i) {
std::cout << vec[i];
}
That part simply prints all the elements of the vector. auto automatically determines what data structure it is given the parameters that define it. In this case, it is being used as a vector<int>::iterator. Mostly, this is used in other data structures, such as a map or a set, since those don't support random access. In a vector, you can simply do
for(int i = 0; i < vec.size(); i++)
{
cout << vec[i] << " ";
}
I have created a set of pairs in C++ to hold potentially colliding pairs of particles for a simple particle simulation as follows:
std::set<std::pair<int, int>> uniquePairs;
Once populated I want to iterate through it ONLY for the live particles in the simulation to check the distances between them for interaction later. I can iterate through the complete set like so...
std::set<std::pair<int,int>>::iterator it;
for (it = uniquePairs.begin(); it != uniquePairs.end(); ++it)
{
std::cout << it->first << std::endl;
}
BUT, this will throw up a vector 'out of range' error since I would be trying to access particles that are not yet alive. Therefore I want to be able to access the list UP TO the same number of live particles .. i.e N = particles.size().
Please help,
Many thanks!
Not absolutely clear in the question, If the question is, 'How to iterate on first N elements of a container?', below is the way to do it.
void foo(std::set<std::pair<int,int>>& uniquePairs, int N) {
auto it = uniquePairs.begin();
for (int i = 0; i < N; ++i)
{
std::cout << it->first << std::endl;
++it;
assert(it != uniquePairs.end());
}
}
CC: https://gcc.godbolt.org/z/tSHQYP
For instance:
vector<int> something;
//imagine i add some elements to the vector here
int* pointy;
for (int i = 0; i < something.size(); pointy = &something[i++]) {
//do some work with pointy
}
it seems to work and saves me a line but is there any danger of weird bugs popping up down the line because of this?
This may not be legal, because pointy is unassigned on the first iteration. If the loop does not dereference pointy during the initial iteration, it may be OK, but it is not possible to tell without seeing the body of the loop.
Since you are using std::vector, using iterators would save you another line, because you wouldn't need to declare pointy. You would be able to determine the offset without i by subtracting something.begin() from the current iterator:
for (vector<int>::iterator iter = something.begin() ; iter != something.end() ; ++iter) {
cout << "Item at index " << (iter - something.begin()) << " is " << *iter << endl;
}
Yes, that is dangerous, as dasblinkenlight pointed out. But there's a simpler way to eliminate this kind of problems.
Write your code for simplicity and readability first. Compressing your loop into the smallest possible number of lines won't add anything in terms of performance, and even if it did, you shouldn't care as long as your profiler doesn't tell you that your loop is a bottleneck.
On the other hand, it will make your code harder to read and, possibly, more prone to bugs (as you've probably noticed).
In C++11, consider using a range-based for loop:
for (int& p : something)
{
// ...
}
In C++03, consider using std::for_each(), or a classical loop based on iterators:
for (std::vector<int>::iterator i = something.begin(); i != something.end(); ++i)
{
// use *i to refer to the current pointy
// use (i - something.begin()) to get its index
// ...
}
It is very dangerous, because i is not unsigned. It can blow up in some rare cases. :)
Is this safe really depends on what you are after.
pointy is going to be a pointer to an element in the vector.
This means that if you change the value of pointy, or what it points to be more specific, you are actually changing the content of the vector for that specific element.
As for me, I like to handle std::vector like this for larger Objects:
std::vector<int*> mynumbers;
//add elements here like this:
int somenumber = 5;
mynumbers.push_back(&somenumber);
for(int i=0;i<elemnts.size();i++)
{
cout << "Element Nr. " << i << ": " << *elements.at(i) << endl;
//modify like this:
*elements.at(i) = 0;
}
The pointer instead of the variable itself is because std::vector handles pointers faster than large objects itself, but for int, this doesn't really make much difference so you can also do it like this:
std::vector<int> mynumbers;
mynumbers.push_back(5);
int* pointy
for(int i=0;i<elemnts.size();i++)
{
pointy = &elements.at(i);
}
Works great for me!
The goal is to access the "nth" element of a vector of strings instead of the [] operator or the "at" method. From what I understand, iterators can be used to navigate through containers, but I've never used iterators before, and what I'm reading is confusing.
If anyone could give me some information on how to achieve this, I would appreciate it. Thank you.
You need to make use of the begin and end method of the vector class, which return the iterator referring to the first and the last element respectively.
using namespace std;
vector<string> myvector; // a vector of stings.
// push some strings in the vector.
myvector.push_back("a");
myvector.push_back("b");
myvector.push_back("c");
myvector.push_back("d");
vector<string>::iterator it; // declare an iterator to a vector of strings
int n = 3; // nth element to be found.
int i = 0; // counter.
// now start at from the beginning
// and keep iterating over the element till you find
// nth element...or reach the end of vector.
for(it = myvector.begin(); it != myvector.end(); it++,i++ ) {
// found nth element..print and break.
if(i == n) {
cout<< *it << endl; // prints d.
break;
}
}
// other easier ways of doing the same.
// using operator[]
cout<<myvector[n]<<endl; // prints d.
// using the at method
cout << myvector.at(n) << endl; // prints d.
In C++-11 you can do:
std::vector<int> v = {0, 1, 2, 3, 4, 5};
for (auto i : v)
{
// access by value, the type of i is int
std::cout << i << ' ';
}
std::cout << '\n';
See here for variations: https://en.cppreference.com/w/cpp/language/range-for
Typically, iterators are used to access elements of a container in linear fashion; however, with "random access iterators", it is possible to access any element in the same fashion as operator[].
To access arbitrary elements in a vector vec, you can use the following:
vec.begin() // 1st
vec.begin()+1 // 2nd
// ...
vec.begin()+(i-1) // ith
// ...
vec.begin()+(vec.size()-1) // last
The following is an example of a typical access pattern (earlier versions of C++):
int sum = 0;
using Iter = std::vector<int>::const_iterator;
for (Iter it = vec.begin(); it!=vec.end(); ++it) {
sum += *it;
}
The advantage of using iterator is that you can apply the same pattern with other containers:
sum = 0;
for (Iter it = lst.begin(); it!=lst.end(); ++it) {
sum += *it;
}
For this reason, it is really easy to create template code that will work the same regardless of the container type.
Another advantage of iterators is that it doesn't assume the data is resident in memory; for example, one could create a forward iterator that can read data from an input stream, or that simply generates data on the fly (e.g. a range or random number generator).
Another option using std::for_each and lambdas:
sum = 0;
std::for_each(vec.begin(), vec.end(), [&sum](int i) { sum += i; });
Since C++11 you can use auto to avoid specifying a very long, complicated type name of the iterator as seen before (or even more complex):
sum = 0;
for (auto it = vec.begin(); it!=vec.end(); ++it) {
sum += *it;
}
And, in addition, there is a simpler for-each variant:
sum = 0;
for (auto value : vec) {
sum += value;
}
And finally there is also std::accumulate where you have to be careful whether you are adding integer or floating point numbers.
Vector's iterators are random access iterators which means they look and feel like plain pointers.
You can access the nth element by adding n to the iterator returned from the container's begin() method, or you can use operator [].
std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();
int sixth = *(it + 5);
int third = *(2 + it);
int second = it[1];
Alternatively you can use the advance function which works with all kinds of iterators. (You'd have to consider whether you really want to perform "random access" with non-random-access iterators, since that might be an expensive thing to do.)
std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();
std::advance(it, 5);
int sixth = *it;
Here is an example of accessing the ith index of a std::vector using an std::iterator within a loop which does not require incrementing two iterators.
std::vector<std::string> strs = {"sigma" "alpha", "beta", "rho", "nova"};
int nth = 2;
std::vector<std::string>::iterator it;
for(it = strs.begin(); it != strs.end(); it++) {
int ith = it - strs.begin();
if(ith == nth) {
printf("Iterator within a for-loop: strs[%d] = %s\n", ith, (*it).c_str());
}
}
Without a for-loop
it = strs.begin() + nth;
printf("Iterator without a for-loop: strs[%d] = %s\n", nth, (*it).c_str());
and using at method:
printf("Using at position: strs[%d] = %s\n", nth, strs.at(nth).c_str());