nested iterator loop, why are iterators equal? - c++ - c++

I want to construct nested loops over arrays of objects, having a rather complex data structure. Because I use arrays, I want to make use of their iterators. After I got unexpected results I boiled down the problem to the following code snippet, that shows my iterators to be equal when I expect them to be different:
vector<int> intVecA;
vector<int> intVecB;
intVecA.push_back(1);
intVecA.push_back(2);
intVecB.push_back(5);
intVecB.push_back(4);
Foo fooOne(intVecA);
Foo fooTwo(intVecB);
vector<int>::const_iterator itA = fooOne.getMyIntVec().begin();
vector<int>::const_iterator itB = fooTwo.getMyIntVec().begin();
cout << "The beginnings of the vectors are different: "
<< (fooOne.getMyIntVec().begin() == fooTwo.getMyIntVec().begin()) << endl;
cout << (*(fooOne.getMyIntVec().begin()) == *(fooTwo.getMyIntVec().begin())) << endl;
cout << (&(*(fooOne.getMyIntVec().begin())) == &(*(fooTwo.getMyIntVec().begin()))) << endl;
cout << "But the iterators are equal: "
<< (itA==itB) << endl;
This produces:
The beginnings of the vectors are different: 0
0
0
But the iterators are equal: 1
This behaviour does not make sense to me and I'd be happy about hearing an explanation.
Foo is a simple object containing a vector and getter function for it:
class Foo {
public:
Foo(std::vector<int> myIntVec);
std::vector<int> getMyIntVec() const {
return _myIntVec;
}
private:
std::vector<int> _myIntVec;
};
Foo::Foo(std::vector<int> myIntVec) {
_myIntVec = myIntVec;
}
When first copying the vectors the problem vanishes. Why?
vector<int> intVecReceiveA = fooOne.getMyIntVec();
vector<int> intVecReceiveB = fooTwo.getMyIntVec();
vector<int>::const_iterator newItA = intVecReceiveA.begin();
vector<int>::const_iterator newItB = intVecReceiveB.begin();
cout << "The beginnings of the vectors are different: "
<< (intVecReceiveA.begin() == intVecReceiveB.begin()) << endl;
cout << "And now also the iterators are different: "
<< (newItA==newItB) << endl;
produces:
The beginnings of the vectors are different: 0
And now also the iterators are different: 0
Further notes:
I need these nested loops in functions which need to be extremely efficient regarding computation time, thus I would not want to do unnecessary operations. Since I'm new to c++ I do not know whether copying the vectors would actually take additional time or whether they would be copied internally anyway. I'm also thankful for any other advice.

The problem is that your accessor in Foo:
std::vector<int> getMyIntVec() const {
return _myIntVec;
}
I doesn't return _myIntVec, it returns a copy of myIntVec.
Instead it should look like:
const std::vector<int>& getMyIntVec() const {
return _myIntVec;
}
Otherwise when you create iterators they are created from copies that are directly thrown away so your C++ compiler reuses the address. That is why you get "equal" iterators, at least I think so.

You realize that you compare things the wrong way round? If you compare a == b, even if you write
cout << "a is different from b: " << (a==b) << endl;
The output will tell if the two elements are the same not different. To check if two things are different use != instead of ==.

The reason for this is that it is undefined behaviour to compare two iterators which refer to elements in different containers. So, there is no guarantee what you will get. This comes from the fact that getMyIntVec returns a copy of _MyIntVec and you assign these copies to new instances of vector<int>, so these are indeed iterators of two different copies of the _MyIntVec member.
According to the standard:
§ 24.2.1
An iterator j is called reachable from an iterator i if and only if there is a finite sequence of applications of
the expression ++i that makes i == j. If j is reachable from i, they refer to elements of the same sequence.
and a bit later in the standard:
§ 24.2.5
The domain of == for forward iterators is that of iterators over the same underlying sequence.
This has already been answered in this question

You have a serious logic problem here:
cout << "The beginnings of the vectors are different: "
<< (fooOne.getMyIntVec().begin() == fooTwo.getMyIntVec().begin()) << endl;
If they are equal, it will output 1 instead of 0 which you normally expect.

Related

Iterators and range based for loops

I'm trying to understand iterators and different ways to iterate over elements in different containers. What's the difference between these two options?
for(auto it = myArray.begin(); it < myArray.end(); it++){
std::cout << *it << std::endl;
}
for(auto it = myArray.begin(); it != myArray.end(); it++){
std::cout << *it << std::endl;
}
When using the second option my editor suggests using a range based for loop in stead, which made me realise I don't know the difference.
for(int & it : myArray){
std::cout << it << std::endl;
}
What's the difference between these two options?
Not all types of input iterators are comparable using the < operator (only random-access iterators are, but not all iterators are random-access). All input iterators are comparable using the == and/or != operator, though.
When using the second option my editor suggests using a range based for loop instead
As you should. A range-for loop uses iterators internally, similar to your second for loop. The loop variable is the dereferenced value, not the iterator itself. A range-for loop does not expose access to its internal iterators.

How should I loop over the elements of a C++ container in reverse order? [duplicate]

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...

How come 2 uninitialized std::set::iterator are equal?

When std::set<>::iterator is uninitialized, it is not equal to any other iterator in the set, but it is equal to other uninitialized iterators.
Is this GCC-specific implementation? (Is the uninitialized iterator actually initialized to an invalid value?)
#include <stdio.h>
#include <iostream>
#include <set>
#include <vector>
int main()
{
std::set<int> s;
std::set<int>::reverse_iterator inv = s.rend();
std::cout << (inv == s.rend()) << "\n";
std::cout << (inv == s.rbegin()) << "\n";
s.insert(5);
std::cout << (inv == s.rend()) << "\n";
std::cout << (inv == s.rbegin()) << "\n";
// invalidate
inv = std::set<int>::reverse_iterator();
std::cout << (inv == s.rend()) << "\n";
std::cout << (inv == s.rbegin()) << "\n";
auto inv2 = std::set<int>::reverse_iterator();
std::cout << (inv == inv2) << "!!!\n";
return 0;
}
prints:
1
1
0
1
0
0
1!!!
Live example: https://onlinegdb.com/r1--46u_B
How come 2 uninitialized std::set::iterator are equal?
They are not uninitialised. They are value initialised. A value initialised iterator is singular: it does not point to any container.
Behaviour of reading an uninitialised value would be undefined, but that's not what you do in the program.
it is not equal to any other iterator in the set
Comparison between input iterators is only defined for iterators to the same range. A singular iterator does not point to same range as any non singular iterator, so the comparison is undefined.
but it is equal to other uninitialized iterators.
Two singular iterators always compare equal.
Is this a GCC-specific, non-portable implementation?
Comparing singular iterator to non singular is undefined. Undefined behaviour is generally "non-portable", even within the same compiler version (unless compiler specifies the behaviour in which case it is non-portable to other compilers).
Singular iterators in general are standard since C++14, for all forward iterators.
the question is: Is this GCC-specific? I am NOT asking if this is UB (it is!)
UB is UB.
By definition, the result you see is potentially unique to that particular run of code on that particular day.
Even if no other implementation ever manifested this behaviour, that doesn't matter, because you can't even rely on it on yours.
Worse, by relying on it, you are breaking a contract, and other parts of your program can break as a result.
So:
Is this a GCC-specific, non-portable implementation?
Yes.

how the iterator in c++ could be printed?

Suppose, I have declared a vector in C++ like this:
vector<int>numbers = {4,5,3,2,5,42};
I can iterate it through the following code:
for (vector<int>::iterator it = numbers.begin(); it!=numbers.end(); it++){
// code goes here
}
Now, I would talk about coding in the block of for loop.
I can access and change any value using this iterator. say, I want to increase every value by 10 and the print. So, the code would be:
*it+=10;
cout << *it << endl;
I can print the address of both iterator and elements that are being iterated.
Address of iterator can be printed by:
cout << &it << endl;
Address of iterated elements can be printed by:
cout << &(*it) << endl;
But why the iterator itself could not printed by doing the following?
cout << it <<endl;
At first I thought the convention came from JAVA considering the security purpose. But if it is, then why I could print it's address?
However, Is there any other way to do this? If not, why?
Yes, there is a way to do it!
You can't print the iterator because it is not defined to have a value.
But you can perform arithematic operations on them and that helps you to print the value (of the iterator).
Do the following.
cout << it - v.begin();
Example:
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
using namespace std;
int main () {
vector<int> v = {20,3,98,34,20,11,101,201};
sort (v.begin(), v.end());
vector<int>::iterator low,up;
low = lower_bound (v.begin(), v.end(), 20);
up = upper_bound (v.begin(), v.end(), 20);
std::cout << "lower_bound at position " << (low - v.begin()) << std::endl;
std::cout << "upper_bound at position " << (up - v.begin()) << std::endl;
return 0;
}
Output of the above code:
lower_bound at position 2
upper_bound at position 4
Note: this is just a way to get things done and no way I have claimed that we can print the iterator.
...
There is no predefined output operator for the standard iterators because there is no conventional meaning of printing an iterator. What would you expect such an operation to print? While you seem to expect to see the address of the object the iterator refers to, I find that not clear at all.
There is no universal answer to that, so the committee decided not to add a those operators. (The last half sentence is a guess, I am not part of the committee.)
If you want to print those iterators, I would define a function like print(Iterator); (or something like this, whatever fits your needs) that does what you want. I would not add an operator << for iterators for the reason I mentioned above.
why the iterator itself could not printed by doing the following?
Because, it is not defined to a value internally.
Is there any other way to do this?
Basically, the compiler does not facilitate it by default, you may try to edit the compiler code! But it is too terrific you know!
If not, why?
Because it has no well-defined way to express it.
You can't print the iterator because it is not defined to have a value. But you can perform arithematic operations on them and that helps you to print the value (of the iterator).

C++ arrays [from:to]

How can i do that in C++?
in python is
example = [u'one', u'two', u'three', u'four']
print example[1:3]
How can i do that in C++ (i missing this function)
I need rewrite this to C++
while i<len(a)-1:
if (a[i]=='\x00' or a[i]=='\x04') and (eval("0x"+(a[i-1].encode("hex"))) in range(32-(4*eval((a[i].encode("hex")))),128-(12*eval((a[i].encode("hex")))))):
st+=a[i-1:i+1]
i+=2;continue
elif st=='':
i+=1;continue
elif len(st)>=4 and (a[i-1:i+1]=='\x00\x00' or a[i-1:i+1]=='\x0a\x00' or a[i-1:i+1]=='\x09\x00' or a[i-1:i+1]=='\x0d\x00'):
s.STRINGS.append([st.decode("utf-16le"),0xffffff])
s.INDEX.append(iCodeOffset+i-1-len(st))
st=''
i=i-1;continue
else:
st=''
i=i-1;continue
I need list of strings from binary files without using string.exe
THX for advance
Benecore
Here is a function that returns a new spliced vector given then old one. It does only the most basic splicing (from:to), and only in one direction (not sure if from is greater than to but I believe python reverses the output).
template<typename T>
std::vector<T> splice(const std::vector<T> in, int from, int to)
{
if (to < from) std::swap(to, from);
std::vector<T> ret(to - from + 1);
for (to -= from; to + 1; to--)
{
ret[to] = in[from + to];
}
return ret;
}
First of all, there is no immediate replacement for this in C++, as C++ is not python and has its own idioms that work differently.
To begin with, for strings you can use the specific std::string::substr.
For more generic containers you should know C++ usually works iterator based when operating on elements of said container. For example suppose you want to compare elements in a vector, you'd do something like the following:
#include <iostream>
#include <algorithm>
#include <vector>
int main()
{
std::vector<int> a = {1,2,3,4};
std::vector<int> b = {1,2,10,4};
std::cout << "Whole vectors equal? " << (std::equal(a.begin(), a.end(), b.begin())?"yes":"no") << std::endl;
}
Now, suppose we only want to compare the first two values (like [:2]), Then we would rewrite the last statement to something like this:
std::cout << "First 2 values equal? " << (std::equal(a.begin(), a.begin()+2, b.begin())?"yes":"no") << std::endl;
Suppose we want to compare the last two values we would do this:
std::cout << "Last 2 values equal? " << (std::equal(a.end()-2, a.end(), b.begin())?"yes":"no") << std::endl;
See the pattern emerging? x.begin()+i,x.begin()+j is roughly equal to [i:j], and x.end()-i,x.end()-j) is roughly equal to [-i,-j]. Note that you can mix these of course.
So in general when working on containers you will work on a range of iterators and this iterator range can be specified very much alike to python's list splicing. It is more verbose and it is another idiom (spliced lists are lists again but iterators are no containers), but you get the same result.
Some final notes:
I wrote x.begin() to make the code a bit clearer, you can also write std::begin(x), which is more generic and also works on arrays. The same goes for std::end
Take a look to the algorithms library before writing your own for loops over iterators.
Yes you can write your own for loops (something like for(auto it = a.begin(); it != a.end(); it++), but often it's easier and more consistent to pass a function or lambda to std::foreach
Really remember C++ is not python or vice versa.