This is a question that goes to how BOOST_FOREACH checks it's loop termination
cout << "Testing BOOST_FOREACH" << endl;
vector<int> numbers; numbers.reserve(8);
numbers.push_back(1); numbers.push_back(2); numbers.push_back(3);
cout << "capacity = " << numbers.capacity() << endl;
BOOST_FOREACH(int elem, numbers)
{
cout << elem << endl;
if (elem == 2) numbers.push_back(4);
}
cout << "capacity = " << numbers.capacity() << endl;
gives the output
Testing BOOST_FOREACH
capacity = 8
1
2
3
capacity = 8
But what about the number 4 which was inserted half way through the loop? If I change the type to a list the newly inserted number will be iterated over. The vector push_back operation will invalidate any pointers IF a reallocation is required, however that is not happening in this example. So the question I guess is why does the end() iterator appear to only be evaluated once (before the loop) when using vector but has a more dynamic evaluation when using a list?
Under the covers, BOOST_FOREACH uses
iterators to traverse the element
sequence. Before the loop is executed,
the end iterator is cached in a local
variable. This is called hoisting, and
it is an important optimization. It
assumes, however, that the end
iterator of the sequence is stable. It
usually is, but if we modify the
sequence by adding or removing
elements while we are iterating over
it, we may end up hoisting ourselves
on our own petard.
http://www.boost.org/doc/libs/1_40_0/doc/html/foreach/pitfalls.html
If you don't want the end() iterator to change use resize on the vector rather than reserve.
http://www.cplusplus.com/reference/stl/vector/resize/
Note that then you wouldn't want to push_back but use the operator[] instead. But be careful of going out of bounds.
The question was raised in the comments as to why the Microsoft debug runtime raises an assertion during iteration over the vector but not over the list. The reason is that insert is defined differently for list and vector (note that push_back is just an insert at the end of the sequence).
Per the C++ standard (ISO/IEC 14882:2003 23.2.4.3, vector modifiers):
[on insertion], if no reallocation happens, all the iterators and references before the insertion point remain valid.
(23.2.2.3, list modifiers):
[insert] does not affect the validity of iterators and references.
So, if you use push_back (and are sure that it's not going to cause a reallocation), it's okay with either container to continue using your iterator to iterate over the rest of the sequence.
In the case of the vector, however, it's undefined behavior to use the end iterator that you obtained before the push_back.
This is a roundabout answer to the question; it's a direct answer to the discussion in the question's comments.
boost's foreach will terminate when it's iterator == numbers.end()
Be careful though, calling push_back can/will invalidate any current iterators you have.
Related
Sorry for naive questions, is it OK to insert an empty set to another set using range function or it is an undefied behavior ?
Test run in https://ideone.com/RNGIFT seems fine, checking the reference saying
If the container is empty, the returned iterator will be equal to end().
#include <iostream>
#include <set>
using namespace std;
int main() {
std::set<string> to_be_inserted;
std::set<string> res;
cout << "check everything is fine" << endl;
res.insert(to_be_inserted.begin(), to_be_inserted.end());
cout << "how about now ?" << endl;
return 0;
}
Yes, most things in C++ relating to iterators will work this way in edge cases such as empty containers so that algorithms relying on the begin and end member functions on containers do not require special code in such circumstances.
Since begin will return the end iterator in the case of the set being empty as you showed, it will effectively make a range of [end, end), which has a length of 0 (as can be checked by functions like std::distance) thus preforming no insertion operations (while also being defined behavior).
This can be seen in practice in a standard library implementation, such as libc++ here where that specific overload of insert walks down the range with a for loop which has an exit condition of the two iterators (first and last) being equal, inserting elements as it goes. In the case of passing an empty range like that to it where the first and last are equal, it'll not even enter the loop.
I have a small problem with lambda expression while using remove_if on std::vector
I have a following piece of code :
std::remove_if( openList.begin(), openList.end(),
[&](BoardNode& i){
std::cout<< i.getCoordinates() << std::endl;
std::cout<< currentNode.getCoordinates() << std::endl;
return i.getCoordinates() == currentNode.getCoordinates(); }
);
There is no compiler error with this, but the elements which return true from the above statement won't be removed from the vector;
I get printed on the screen e.g.
[5,5]
[5,5]
but the openList remains as it was.
std::remove_if doesn't erase anything from the vector, since it doesn't have access to it. Instead, it moves the elements you want to keep to the start of the range, leaving the remaining elements in a valid but unspecified state, and returns the new end.
You can use the "erase-remove" idiom to actually erase them from the vector:
openList.erase(
std::remove_if(
openList.begin(),
openList.end(),
[&](BoardNode& i){return i.getCoordinates() == currentNode.getCoordinates();}),
openList.end());
I think you intend to remove items from the vector. But what you do, would not really remove the items from the vector, which makes you think that the lambda doesn't work. You need to use erase() member function in conjunction with std::remove.
In other words, you have to use erase-remove idiom as:
v.erase(std::remove_if(v.begin(), v.end(), your-lambda-goes-here), v.end());
Removing is done by shifting the elements in the range in such a way
that elements to be erased are overwritten. The elements between the
old and the new ends of the range have unspecified values. An iterator
to the new end of the range is returned. Relative order of the
elements that remain is preserved.
http://en.cppreference.com/w/cpp/algorithm/remove
Also, check the example on that link.
I have a vector declared as
std::vector<int> MyVector;
MyVector.push_back(5);
MyVector.push_back(6);
MyVector.push_back(7);
How do should I use it in a for loop?
By iterating it with an iterator?
for (std::vector<int>::iterator it=MyVector.begin(); it!=MyVector.end(); ++it)
{
std::cout << "Vector element (*it): " << *it << std::endl;
}
Or by its access iterator?
for (std::vector<int>::size_type i=0; i<MyVector.size(); i++)
{
std::cout << "Vector element (i) : " << MyVector.at(i) << std::endl;
}
In examples I found on internet both of them are used. Is one of them superior to the other under all conditions? If not, when should I prefer one of them over the other?
The first format is more generic format for iterating over standard library containers so it is more common and intuitive. If you need to change your container then this iterating code remains unimpacted.It will work for every standard library container type, thus it gives you more generic code.
In second format, std::vector::at() checks for the bounds each time it gets called on every iteration, so it may be a little detrimental to performance. This overhead is not present in the first format as there is no bounds checking involved.Note that same is the case with using operator[].
Note the performance lag though is not as much as you will notice it unless you are operating on a huge data.
Using std::vector's [] operator is probably faster because using std::vector::at() inside a for loop checks the vector's size twice (in the for loop and in std::vector::at()'s bounds checking).
The first method can be used in other containers and thus can help you much when you change your container type.
If you use C++11, use range-based loops.
First if you have C++11, use a range-based for:
for (auto i : MyVector)
{
std::cout << i;
}
Or BOOST_FOREACH in C++03:
BOOST_FOREACH(int& i, MyVector)
{
std::cout << i;
}
Or std::copy:
std::copy(MyVector.begin(),
MyVector.end(),
std::ostream_iterator<int>(std::cout, "\n"));
As for, the question at hand, at() checks that the index is within bounds and throws an exception if it isn't. So, do not use it unless you need that extra checking. The first way you have it is standard and works well. Some people are pedantic and even it write it like so:
for (std::vector<int>::iterator it=MyVector.begin(), end = MyVector.end(); it!= end; ++it)
{
std::cout << "Vector element (*it): " << *it << std::endl;
}
In the above I cached the end iterator instead of calling end() each loop. Whether this actually makes a performance difference or not, I don't know.
There is no "one is superior to the other" (except that you almost never
want to use at()—at() is only appropriate if there is
something you can really do to recover from the error). The use of
iterator vs. index is largely one of style, and the message you're
passing. The more idiomatic C++ way of doing things would be the
iterator, but people coming from other backgrounds (for example,
mathematicians) will find indexing more idiomatic.
There are where there is a real distinction:
The iterator idiom will work with other types of containers. This
might be relevant if there is a real possibility that you use other
containers.
The indexing idiom can use a single index for several different
containers. If you're iterating through several vector with the same
size, using the indexing idiom makes it clearer that you're accessing
the same element in each of the vector. (Again, this seems to occur
most often in mathematical applications.)
Finally, any time you're really doing random access, or calculating
the element in any way, using indexes is probably more intuitive. (In
such cases, you probably want to do the calculations in int, only
converting to size_t at the last moment.)
Short question: Is the following code unsafe using other compilers than I do (mingw32), or is it valid to use?
list<int> l;
/* add elements */
list<int>::iterator i = l.begin();
i--;
i++;
cout << *i << endl;
...or in other words: is i defined to point to l.begin() after this?
Yes, the code is unsafe. Once you attempt to move before begin() you have caused undefined behavior. Attempting to move "back again" may not work.
A std::list traverses its contents via linked list pointers, so pointer arithmetic is not used to calculate a correct position. The previous position from .begin() will have no data and shouldn't provide any valid traversal mechanisms.
Containers like std::vector have random access iterators and would use pointer arithmetic under the covers, so they would probably give the right result (no problem), but its still a bad idea.
So, it shouldn't work, its undefined, and don't do it even if it does work somehow :)
Am I right in assuming that adding/removing elements to an std::map does not effect the other elements (ie cause them to be relocated in memory) and so that the following is safe:
I looked at various sites with info on the container but only found out about the cases where iterators are invalidated, which I already know...
std::map<std::string,std::string> map;
PopulateMap(map);
std::string &a= map["x"];
AddMoreData(map);
RemoveRandomKeysExceptX(map);
map["x"] = "foo";
std::cout << a << " " << map["x"] << std::endl;//prints "foo foo"
a = "bar";
std::cout << a << " " << map["x"] << std::endl;//prints "bar bar"
I tested some similar code on VC9, which seems to work however that doesn't mean I didn't just get lucky or that it doesn't vary across compilers.
The Standard is clear on this in 23.1.2/8 about associative containers
The insert members shall not affect the validity of iterators and references to the container, and the erase members shall invalidate only iterators and references to the erased elements.
Map has the important property that inserting a new element into a map does not invalidate iterators that point to existing elements.
quote taken from sgi docs.
If the iterators are guaranteed not to change then the values they point at also cannot change.
naveen previously had an answer that was similar to this. Unless there is a mistake in my logic what you are doing is safe.
Edit 2:
See point 3 in sgi docs to see how getting a value from operator [] is the same as getting the value from an iterator.
Yes you can count on this.
// retrieve reference to string stored at "x"
// note that since [] returns a reference, it must insert an element at "x" if
// it doesn't exists (in this case an empty string)
std::string &a= map["x"];
// retrieve reference for "x" again and set value to "foo"
map["x"] = "foo";
// use already stored reference
a = "bar";