In my game engine project, I make extensive use of the STL, mostly of the std::string and std::vector classes.
In many cases, I have to iterate through them. Right now, the way I'm doing it is:
for( unsigned int i = 0; i < theContainer.size(); i ++ )
{
}
Am I doing it the right way?
If not, why, and what should I do instead?
Is size() really executed every loop cycle with this implementation? Would the performance loss be negligible?
C++11 has a new container aware for loop syntax that can be used if your compiler supports the new standard.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
vector<string> vs;
vs.push_back("One");
vs.push_back("Two");
vs.push_back("Three");
for (const auto &s : vs)
{
cout << s << endl;
}
return 0;
}
You might want to look at the standard algorithms.
For example
vector<mylass> myvec;
// some code where you add elements to your vector
for_each(myvec.begin(), myvec.end(), do_something_with_a_vector_element);
where do_something_with_a_vector_element is a function that does what goes in your loop
for example
void
do_something_with_a_vector_element(const myclass& element)
{
// I use my element here
}
The are lots of standard algorithms - see http://www.cplusplus.com/reference/algorithm/ - so most things are supported
STL containers support Iterators
vector<int> v;
for (vector<int>::iterator it = v.begin(); it!=v.end(); ++it) {
cout << *it << endl;
}
size() would be re-computed every iteration.
For random-access containers, it's not wrong.
But you can use iterators instead.
for (string::const_iterator it = theContainer.begin();
it != theContainer.end(); ++it) {
// do something with *it
}
There are some circumstances under which a compiler may optimize away the .size() (or .end() in the iterator case) calls (e.g. only const access, function is pure). But do not depend on it.
Usually the right way to "iterate" over a container is using "iterators". Something like
string myStr = "hello";
for(string::iterator i = myStr.begin(); i != myStr.end(); ++i){
cout << "Current character: " << *i << endl;
}
Of course, if you aren't going to modify each element, it's best to use string::const_iterator.
And yes, size() gets called every time, and it's O(n), so in many cases the performance loss will be noticeable and it's O(1), but it's a good practice to calculate the size prior to the loop than calling size every time.
No, this is not the correct way to do it. For a ::std::vector or a ::std::string it works fine, but the problem is that if you ever use anything else, it won't work so well. Additionally, it isn't idiomatic.
And, to answer your other question... The size function is probably inline. This means it likely just fetches a value from the internals of ::std::string or ::std::vector. The compiler will optimize this away and only fetch it once in most cases.
But, here is the idiomatic way:
for (::std::vector<Foo>::iterator i = theContainer.begin();
i != theContainer.end();
++i)
{
Foo &cur_element = *i;
// Do stuff
}
The ++i is very important. Again, for ::std:vector or ::std::string where the iterator is basically a pointer, it's not so important. But for more complicated data structures it is. i++ has to make a copy and create a temporary because the old value needs to stick around. ++i has no such issue. Get into the habit of always using ++i unless you have a compelling reason not to.
Lastly, theContainer.end() will also be generally optimized out of existence. But you can force things to be a little better by doing this:
const ::std::vector<Foo>::iterator theEnd = theContainer.end();
for (::std::vector<Foo>::iterator i = theContainer.begin(); i != theEnd; ++i)
{
Foo &cur_element = *i;
// Do stuff
}
Of course, C++0x simplifies all of this considerably with a new syntax for for loops:
for (Foo &i: theContainer)
{
// Do stuff with i
}
These will work on standard fix-sized arrays as well as any type that defines begin and end to return iterator-like things.
Native for-loop (especially index-based) - it's C-way, not C++-way.
Use BOOST_FOREACH for loops.
Compare, for container of integers:
typedef theContainer::const_iterator It;
for( It it = theContainer.begin(); it != theContainer.end(); ++it ) {
std::cout << *it << std::endl;
}
and
BOOST_FOREACH ( int i, theContainer ) {
std::cout << i << std::endl;
}
But this is not perfect way. If you can do your work without loop - you MUST do it without loop. For example, with algorithms and Boost.Phoenix:
boost::range::for_each( theContainer, std::cout << arg1 << std::endl );
I understand that these solutions bring additional dependencies in your code, but Boost is 'must-have' for modern C++.
You're doing it OK for vectors, although that doesn't translate into the right way for other containers.
The more general way is
for(std::vector<foo>::const_iterator i = theContainer.begin(); i != theContainer.end; ++i)
which is more typing than I really like, but will become a lot more reasonable with the redefinition of auto in the forthcoming Standard. This will work on all standard containers. Note that you refer to the individual foo as *i, and use &*i if you want its address.
In your loop, .size() is executed every time. However, it's constant time (Standard, 23.1/5) for all standard containers, so it won't slow you down much if at all. Addition: the Standard says "should" have constant complexity, so a particularly bad implementation could make it not constant. If you're using such a bad implementation, you've got other performance issues to worry about.
Related
This question already has answers here:
Iterating C++ vector from the end to the beginning
(13 answers)
Closed 2 years ago.
Suppose I'm a newbie C++ programmer. I have a C++ container; say, a vector:
std::vector<int> vec { 12, 34, 56, 78 };
I know I can iterate over all of the elements with a simple loop:
for(std::vector<int>::size_type i = 0; i < vec.size(); i++) {
std::cout << vec[i] << '\n';
}
and maybe I've even learned a little about Modern C++, so I know I can use a ranged-for loop:
for(auto x : vec) {
std::cout << x << '\n';
}
But now, I want to iterate over the elements in reverse order. The range-based for loop won't work as such. With a plain loop, I have to be careful and avoid underflow, so perhaps something like this? :
for(std::vector<int>::size_type i = 0; i < vec.size(); i++) {
std::cout << vec[vec.size() - i] << '\n';
}
but - I don't like having the loop counter mean the opposite of what we're looking at. But if I started i at vec.size()-1, I would risk underflow after the last element. So I would need to do this, maybe?
for(std::vector<int>::size_type i = vec.size(); i > 0 ; i--) {
std::cout << vec[i - 1] << '\n';
}
well, that doesn't feel right either. What idioms should I use for reverse iteration, which are safe (i.e. difficult to get wrong) , aesthetically pleasing and reasonable terse?
Notes:
I tried to phrase the title to be as simple as possible (rather than saying "reverse-iterate a container").
Motivated by this question, where a naive reverse-iteration loop has a bug.
I do not want to make a copy of the container with the elements and reverse and iterate over that the usual way.
I didn't use auto& or const auto& in the loops above since newbie coders often don't know about them.
Well, first of all, about your two snippets: Part of the problem is that they're a bit bug prone for actual newbies - the integer underflow, off-by-one in the comparison, forgetting what i signifies and using it as a plain index etc. So I would definitely recommend something else. Also, those snippets may invoke vec.size() many times, which, if the compiler isn't optimizing well enough, would mean a bunch of redundant work.
Option 1: Use iterators
You can reverse-iterate over a container using a pair of iterators (std::rbegin and std::rend, and their constant variants) which represent the reversal of the container's order of elements. Here's what that looks like:
for(auto it = std::crbegin(vec); it != std::crend(vec); it++) {
std::cout << *it << '\n';
}
I made this option the first because it's (mostly) compatible with C++98. We didn't have std::rbegin() and std::crbegin() then, but we did have an rbegin() method for std::vector. std::crbegin() was introduced in C++11
Option 2: Using C++11 (and later) ranged-for loops
You can massage your container - without making a copy of it (although possibly with some payment of time), so that you can use the result in ranger for loop. The answers to this SO question describe several ways to do so, enabling the following code:
auto reverse_view = /* magic involving vec; and not making a copy */
for(auto x : reverse_view) {
std::cout << *it << '\n';
}
They involve either using an "infrastructural" library (namely Boost), or writing a few lines of code which return an iterator pair in an std::pair - which is enough for C++ to use in a ranged-for loop.
Option 3: Using ranged-for and C++20's ranges support
Finally, in C++20, this all becomes easier - with ranges support and std::ranges::reverse_view:
auto reverse_view = std::ranges::reverse_view{vec};
for (const auto& x : reverse_view) {
std::cout << x << '\n';
}
Performance note
Reverse-iterating can in some cases be expensive - because moving backwards, or finding the end of the container, is not always trivial or free. Think of a unidirectional list (where each element comes with a pointer to the next one) - whenever you want to go backwards, you need to traverse the whole list up to your current element to know where the previous element is located. Not all containers are like vectors...
In terms of space-time complexity which of the following is best way to iterate over a std::vector and why?
Way 1:
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
/* std::cout << *it; ... */
}
Way 2:
for(std::vector<int>::size_type i = 0; i != v.size(); i++) {
/* std::cout << v[i]; ... */
}
Way 3:
for(size_t i = 0; i != v.size(); i++) {
/* std::cout << v[i]; ... */
}
Way 4:
for(auto const& value: a) {
/* std::cout << value; ... */
First of all, Way 2 and Way 3 are identical in practically all standard library implementations.
Apart from that, the options you posted are almost equivalent. The only notable difference is that in Way 1 and Way 2/3, you rely on the compiler to optimize the call to v.end() and v.size() out. If that assumption is correct, there is no performance difference between the loops.
If it's not, Way 4 is the most efficient. Recall how a range based for loop expands to
{
auto && __range = range_expression ;
auto __begin = begin_expr ;
auto __end = end_expr ;
for ( ; __begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
The important part here is that this guarantees the end_expr to be evaluated only once. Also note that for the range based for loop to be the most efficient iteration, you must not change how the dereferencing of the iterator is handled, e.g.
for (auto value: a) { /* ... */ }
this copies each element of the vector into the loop variable value, which is likely to be slower than for (const auto& value : a), depending on the size of the elements in the vector.
Note that with the parallel algorithm facilities in C++17, you can also try out
#include <algorithm>
#include <execution>
std::for_each(std::par_unseq, a.cbegin(), a.cend(),
[](const auto& e) { /* do stuff... */ });
but whether this is faster than an ordinary loop depends on may circumstantial details.
Prefer iterators over indices/keys.
While for vector or array there should be no difference between either form1, it is a good habit to get into for other containers.
1 As long as you use [] instead of .at() for accesssing by index, of course.
Memorize the end-bound.
Recomputing the end-bound at each iteration is inefficient for two reasons:
In general: a local variable is not aliased, which is more optimizer-friendly.
On containers other than vector: computing the end/size could be a bit more expensive.
You can do so as a one-liner:
for (auto it = vec.begin(), end = vec.end(); it != end; ++it) { ... }
(This is an exception to the general prohibition on declaring a single variable at a time.)
Use the for-each loop form.
The for-each loop form will automatically:
Use iterators.
Memorize the end-bound.
Thus:
for (/*...*/ value : vec) { ... }
Take built-in types by values, other types by reference.
There is a non-obvious trade-off between taking an element by value and taking an element by reference:
Taking an element by reference avoids a copy, which can be an expensive operation.
Taking an element by value is more optimizer-friendly1.
At the extremes, the choice should be obvious:
Built-in types (int, std::int64_t, void*, ...) should be taken by value.
Potentially allocating types (std::string, ...) should be taken by reference.
In the middle, or when faced with generic code, I would recommend starting with references: it's better to avoid a performance cliff than attempting to squeeze out the last cycle.
Thus, the general form is:
for (auto& element : vec) { ... }
And if you are dealing with a built-in:
for (int element : vec) { ... }
1 This is a general principle of optimization, actually: local variables are friendlier than pointers/references because the optimizer knows all the potential aliases (or absence, thereof) of the local variable.
Addition to lubgr's answer:
Unless you discover via profiling the code in question to be a bottleneck, efficiency (which you probably meant instead of 'effectivity') shouldn't be your first concern, at least not on this level of code. Much more important are code readability and maintainability! So you should select the loop variant that reads best, which usually is way 4.
Indices can be useful if you have steps greater than 1 (whyever you would need to...):
for(size_t i = 0; i < v.size(); i += 2) { ... }
While += 2 per se is legal on iterators, too, you risk undefined behaviour at loop end if the vector has odd size because you increment past the one past the end position! (Generally spoken: If you increment by n, you get UB if size is not an exact multiple of n.) So you need additional code to catch this, while you don't with the index variant...
The lazy answer: The complexities are equivalent.
The time complexity of all solutions is Θ(n).
The space complexity of all solutions is Θ(1).
The constant factors involved in the various solutions are implementation details. If you need numbers, you're probably best off benchmarking the different solutions on your particular target system.
It may help to store v.size() rsp. v.end(), although these are usually inlined, so such optimizations may not be needed, or performed automatically.
Note that indexing (without memoizing v.size()) is the only way to correctly deal with a loop body that may add additional elements (using push_back()). However, most use cases do not need this extra flexibility.
Prefer method 4, std::for_each (if you really must), or method 5/6:
void method5(std::vector<float>& v) {
for(std::vector<float>::iterator it = v.begin(), e = v.end(); it != e; ++it) {
*it *= *it;
}
}
void method6(std::vector<float>& v) {
auto ptr = v.data();
for(std::size_t i = 0, n = v.size(); i != n; i++) {
ptr[i] *= ptr[i];
}
}
The first 3 methods can suffer from issues of pointer aliasing (as alluded to in previous answers), but are all equally bad. Given that it's possible another thread may be accessing the vector, most compilers will play it safe, and re-evaluate [] end() and size() in each iteration. This will prevent all SIMD optimisations.
You can see proof here:
https://godbolt.org/z/BchhmU
You'll notice that only 4/5/6 make use of the vmulps SIMD instructions, where as 1/2/3 only ever use the non-SIMD vmulss instructiuon.
Note: I'm using VC++ in the godbolt link because it demonstrates the problem nicely. The same problem does occur with gcc/clang, but it's not easy to demonstrate it with godbolt - you usually need to disassemble your DSO to see this happening.
For completeness, I wanted to mention that your loop might want to change the size of the vector.
std::vector<int> v = get_some_data();
for (std::size_t i=0; i<v.size(); ++i)
{
int x = some_function(v[i]);
if(x) v.push_back(x);
}
In such an example you have to use indices and you have to re-evaluate v.size() in every iteration.
If you do the same with a range-based for loop or with iterators, you might end up with undefined behavior since adding new elements to a vector might invalidate your iterators.
By the way, I prefer to use while-loops for such cases over for-loops but that's another story.
It depends to a large extent on what you mean by "effective".
Other answers have mentioned efficiency, but I'm going to focus on the (IMO) most important purpose of C++ code: to convey your intent to other programmers¹.
From this perspective, method 4 is clearly the most effective. Not just because there are fewer characters to read, but mainly because there's less cognitive load: we don't need to check whether the bounds or step size are unusual, whether the loop iteration variable (i or it) is used or modified anywhere else, whether there's a typo or copy/paste error such as for (auto i = 0u; i < v1.size(); ++i) { std::cout << v2[i]; }, or dozens of other possibilities.
Quick quiz: Given std::vector<int> v1, v2, v3;, how many of the following loops are correct?
for (auto it = v1.cbegin(); it != v1.end(); ++it)
{
std::cout << v1[i];
}
for (auto i = 0u; i < v2.size(); ++i)
{
std::cout << v1[i];
}
for (auto const i: v3)
{
std::cout << i;
}
Expressing the loop control as clearly as possible allows the developer's mind to hold more understanding of the high-level logic, rather than being cluttered with implementation details - after all, this is why we're using C++ in the first place!
¹ To be clear, when I'm writing code, I consider the most important "other programmer" to be Future Me, trying to understand, "Who wrote this rubbish?"...
All of the ways you listed have identical time complexity and identical space complexity (no surprise there).
Using the for(auto& value : v) syntax is marginally more efficient, because with the other methods, the compiler may re-load v.size() and v.end() from memory every time you do the test, whereas with for(auto& value : v) this never occurs (it only loads the begin() and end() iterators once).
We can observe a comparison of the assembly produced by each method here: https://godbolt.org/z/LnJF6p
On a somewhat funny note, the compiler implements method3 as a jmp instruction to method2.
The complexity is the same for all except the last one that is in theory faster because the end of the container is evaluated only once.
Last one is also the nicest to read and to write, but has the drawback that doesn't give you the index (that is quite often important).
You are however ignoring what I think is a good alternative (it's my preferred one when I need the index and cannot use for (auto& x : v) {...}):
for (int i=0,n=v.size(); i<n; i++) {
... use v[i] ...
}
note that I used int and not size_t and that the end is computed only once and also available in the body as a local variable.
Often when the index and the size are needed then math computations are also performed on them and size_t behaves "strangely" when used for math (for example a+1 < b and a < b-1 are different things).
I am new to the C++ language. I have been starting to use vectors, and have noticed that in all of the code I see to iterate though a vector via indices, the first parameter of the for loop is always something based on the vector. In Java I might do something like this with an ArrayList:
for(int i=0; i < vector.size(); i++){
vector[i].doSomething();
}
Is there a reason I don't see this in C++? Is it bad practice?
The reason why you don't see such practice is quite subjective and cannot have a definite answer, because I have seen many of the code which uses your mentioned way rather than iterator style code.
Following can be reasons of people not considering vector.size() way of looping:
Being paranoid about calling size() every time in the loop
condition. However either it's a non-issue or it can be trivially
fixed
Preferring std::for_each() over the for loop itself
Later changing the container from std::vector to other one (e.g.
map, list) will also demand the change of the looping mechanism,
because not every container support size() style of looping
C++11 provides a good facility to move through the containers. That is called "range based for loop" (or "enhanced for loop" in Java).
With little code you can traverse through the full (mandatory!) std::vector:
vector<int> vi;
...
for(int i : vi)
cout << "i = " << i << endl;
The cleanest way of iterating through a vector is via iterators:
for (auto it = begin (vector); it != end (vector); ++it) {
it->doSomething ();
}
or (equivalent to the above)
for (auto & element : vector) {
element.doSomething ();
}
Prior to C++0x, you have to replace auto by the iterator type and use member functions instead of global functions begin and end.
This probably is what you have seen. Compared to the approach you mention, the advantage is that you do not heavily depend on the type of vector. If you change vector to a different "collection-type" class, your code will probably still work. You can, however, do something similar in Java as well. There is not much difference conceptually; C++, however, uses templates to implement this (as compared to generics in Java); hence the approach will work for all types for which begin and end functions are defined, even for non-class types such as static arrays. See here: How does the range-based for work for plain arrays?
Is there any reason I don't see this in C++? Is it bad practice?
No. It is not a bad practice, but the following approach renders your code certain flexibility.
Usually, pre-C++11 the code for iterating over container elements uses iterators, something like:
std::vector<int>::iterator it = vector.begin();
This is because it makes the code more flexible.
All standard library containers support and provide iterators. If at a later point of development you need to switch to another container, then this code does not need to be changed.
Note: Writing code which works with every possible standard library container is not as easy as it might seem to be.
The right way to do that is:
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
it->doSomething();
}
Where T is the type of the class inside the vector. For example if the class was CActivity, just write CActivity instead of T.
This type of method will work on every STL (Not only vectors, which is a bit better).
If you still want to use indexes, the way is:
for(std::vector<T>::size_type i = 0; i != v.size(); i++) {
v[i].doSomething();
}
Using the auto operator really makes it easy to use as one does not have to worry about the data type and the size of the vector or any other data structure
Iterating vector using auto and for loop
vector<int> vec = {1,2,3,4,5}
for(auto itr : vec)
cout << itr << " ";
Output:
1 2 3 4 5
You can also use this method to iterate sets and list. Using auto automatically detects the data type used in the template and lets you use it.
So, even if we had a vector of string or char the same syntax will work just fine
A correct way of iterating over the vector and printing its values is as follows:
#include<vector>
// declare the vector of type int
vector<int> v;
// insert elements in the vector
for (unsigned int i = 0; i < 5; ++i){
v.push_back(i);
}
// print those elements
for (auto it = v.begin(); it != v.end(); ++it){
std::cout << *it << std::endl;
}
But at least in the present case it is nicer to use a range-based for loop:
for (auto x: v) std::cout << x << "\n";
(You may also add & after auto to make x a reference to the elements rather than a copy of them. It is then very similar to the above iterator-based approach, but easier to read and write.)
There's a couple of strong reasons to use iterators, some of which are mentioned here:
Switching containers later doesn't invalidate your code.
i.e., if you go from a std::vector to a std::list, or std::set, you can't use numerical indices to get at your contained value. Using an iterator is still valid.
Runtime catching of invalid iteration
If you modify your container in the middle of your loop, the next time you use your iterator it will throw an invalid iterator exception.
Here is a simpler way to iterate and print values in vector.
for(int x: A) // for integer x in vector A
cout<< x <<" ";
With STL, programmers use iterators for traversing through containers, since iterator is an abstract concept, implemented in all standard containers. For example, std::list has no operator [] at all.
I was surprised nobody mentioned that iterating through an array with an integer index makes it easy for you to write faulty code by subscripting an array with the wrong index. For example, if you have nested loops using i and j as indices, you might incorrectly subscript an array with j rather than i and thus introduce a fault into the program.
In contrast, the other forms listed here, namely the range based for loop, and iterators, are a lot less error prone. The language's semantics and the compiler's type checking mechanism will prevent you from accidentally accessing an array using the wrong index.
don't forget examples with const correctness - can the loop modify the elements. Many examples here do not, and should use cont iterators. Here we assume
class T {
public:
T (double d) : _d { d } {}
void doSomething () const { cout << _d << endl; return; }
void changeSomething () { ++_d; return; }
private:
double _d;
};
vector<T> v;
// ...
for (const auto iter = v.cbegin(); iter != v.cend(); ++iter) {
iter->doSomething();
}
Note also, that with the C++11 notation, the default is to copy the element. Use a reference to avoid this, and/or to allow for original elements to be modified:
vector<T> v;
// ...
for (auto t : v) {
t.changeSomething(); // changes local t, but not element of v
t.doSomething();
}
for (auto& t : v) { // reference avoids copying element
t.changeSomething(); // changes element of v
t.doSomething();
}
for (const auto& t : v) { // reference avoids copying element
t.doSomething(); // element can not be changed
}
//different declaration type
vector<int>v;
vector<int>v2(5,30); //size is 5 and fill up with 30
vector<int>v3={10,20,30};
//From C++11 and onwards
for(auto itr:v2)
cout<<"\n"<<itr;
//(pre c++11)
for(auto itr=v3.begin(); itr !=v3.end(); itr++)
cout<<"\n"<<*itr;
int main()
{
int n;
int input;
vector<int> p1;
vector<int> ::iterator it;
cout << "Enter the number of elements you want to insert" << endl;
cin >> n;
for (int i = 0;i < n;i++)
{
cin >> input;
p1.push_back(input);
}
for(it=p1.begin();it!=p1.end();it++)
{
cout << *it << endl;
}
//Iterating in vector through iterator it
return 0;
}
conventional form of iterator
If you use
std::vector<std::reference_wrapper<std::string>> names{ };
Do not forget, when you use auto in the for loop, to use also get, like this:
for (auto element in : names)
{
element.get()//do something
}
I have this question that runs in my mind...
I have a std::vector to iterate:
which is the best way (the faster) to iterate?
here is the code using an iterator:
// using the iterator
for( std::vector <myClass*>::iterator it = myObject.begin( ); it != myObject.end( ); it++ )
{
(*it)->someFunction( );
}
and here is 'normal' mode...
// normal loop
for( int i = 0; i < myObject.Size( ); i++ )
{
myObject[i]->someFunction( );
}
thanks for your suggestions!
None of the two will be any faster really, because on most implementations a vector<T>::iterator is just a typedef for T* and size is cached.
But doing ++it instead of it++ is a good habit. The latter involves creating a temporary.
for(std::vector <myClass*>::iterator it = myObject.begin( );
it != myObject.end( );
++it)
^^^^
On other containers such as map, list etc. with nontrivial iterators the difference between postincrement and preincrement might become noticable.
If you really care, you can find out: Just make a single source file with one function with that loop and look at the optimized assembly:
g++ -O2 -S -o ver1.s ver1.cpp
g++ -O2 -S -o ver2.s ver2.cpp
You can directly see the differences! I bet there are none.
That said, you should use the iterator pattern because it's idomatic, generic C++ and it gets you in the right mood -- plus, it works in far more general cases than just vectors! Write it like this:
typedef std::vector<MyClass*> myVec;
for (myVec::const_iterator it = v.begin(), end = v.end(); it != end; ++it)
{
const MyClass & x = **it;
/* ... */
}
In case you're curious, a vector iterator is most likely just going to be a native, raw pointer, so there's really nothing to fear in terms of efficiency, and a lot to be enjoyed from the self-explanatory, algorithmic style!
PS If you have C++0x, say it like this:
for (auto it = v.cbegin(), end = v.cend(); it != end; ++it)
// or
for (const MyClass * & i : v)
The first code will decompose into incrementing a pointer. The second one will increment an index, and index into the array. The first one can use slightly smaller instructions (and thus potentially be faster) assuming the compiler doesn't optimize the second into the first already. But it will be a trivial difference.
Iterators should be preferred, however, not because of speed but because you can then easily move the code to iterate any standard C++ container, not just vector.
However, you've got a few things to improve.
Don't use it++, but ++it. This can be very important in C++ because iterators can end up doing a little more work in post-increment which won't be optimized out as if the type were an int.
Don't constantly call end() or size(). For some iterator types and collections this might not be optimized out and can be very sub-optimal.
Use vector::size_type when you need an index into a vector. int is not guaranteed to be big enough, while size_type was made specifically for that.
So, the better ways to write these are:
// using the iterator
for(std::vector <myClass*>::iterator it = myObject.begin( ), end = myObject.end(); it != end; ++it)
{
(*it)->someFunction( );
}
// normal loop
for(std::vector <myClass*>::size_type i = 0, size = myObject.size(); i < size; ++i)
{
myObject[i]->someFunction( );
}
Here's what I use:
int s = vec.size();
for(int i=0;i<s;i++)
{
T &o = vec[i];
...
}
This loop has the following advantages over other approaches:
it always looks the same (unlike the hacks that change from i++ to ++i)
it's relatively short to write (compared to the iterator version)
the int indexes are useful in your public interface (unlike iterators)
it still always looks the same (unlike stdlib algorithms, where you need documentation to remember the parameters)
it's very old and thus widely used. (originally comes from book "The C programming language" aka K&R)
It doesn't give warnings on most compilers (unlike the loop that was used in the question)
It does have some disadvantages too:
some newer programmers doesn't like it because they think C ways are too old
in a const function, you might need to change it slightly to const T &o = vec[i]; or change the data member mutable
type T changes depending on the use
You can do this:
#include <iostream>
using namespace std;
int main() {
for (int i = 3; i > 0; i--) {
cout << i << "\n";
}
return 0;
}
source https://mockstacks.com/Cpp_For_Loop
today I've been working with Boost::shared_ptr, and I have a question.
vector<shared_ptr<KlasaA> > vec;
vec.push_back(shared_ptr<KlasaA>(new KlasaB));
vec.push_back(shared_ptr<KlasaA>(new KlasaC));
vec.push_back(shared_ptr<KlasaA>(new KlasaC));
vec.push_back(shared_ptr<KlasaA>(new KlasaA));
for (vector<shared_ptr<KlasaA> >::const_iterator c_it = vec.begin();
c_it != vec.end(); ++c_it)
{
cout << c_it->get()->foo(10) << endl;
}
The loop above goes through a vector and polymorphically invokes foo(10).
My question is:
Can...
for (vector<shared_ptr<KlasaA> >::const_iterator c_it = vec.begin();
c_it != vec.end(); ++c_it)
and
cout << c_it->get()->foo(10) << endl;
be expressed in a more concise way? Thanks in advance.
typedef boost::shared_ptr<KlasaA> SharedKlasaA;
typedef vector<SharedKlasaA> KlasaAVector;
KlasaAVector vec;
vec.push_back(SharedKlasaA(new KlasaB));
...
for (KlasaAVector::const_iterator ...
cout << (*c_it)->foo(10);
You could use Boost.Foreach library. Then it will look pretty concise and clear:
BOOST_FOREACH( boost::shared_ptr<KlasaA> v, vec )
{
std::cout << v->foo(10) << std::endl;
}
Your iterator initialization seems about as compact as can be, as far as I can see. If you really want to, you could write the loop function as:
cout << (*c_it)->foo(10) << endl;
This saves only 4 characters, but it does look a bit clearer.
shared_ptr has an implicit downcast constructor, so you can write
vec.push_back(shared_ptr<KlasaB>(new KlasaB));
Notice the shared_ptr type is shared_ptr<KlasaB> and vec expects shared_ptr<KlasaA>.
With this in mind, you can replace shared_ptr constructor with make_shared function call (which may actually be preferred, anyway).
vec.push_back(make_shared<KlasaB>());
This will save you the hassle of typing in a bunch of class names. make_shared accepts arguments which it will forward, so make_shared<X> is a nice replacement for new X.
You may notice that there are potential performance implications here: the make_shared data structure can (will?) be different, and there is an extra implicit conversion, but that may be optimized away by the compiler. Profile and check.
Dependently on compiler you may do such things:
std::foreach(vec.begin(),vec.end(),[](const boost::shared_ptr<KlasaA> &p){
cout<<p->foo(10);
});