1

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.

hmjd
  • 120,187
  • 20
  • 207
  • 252
user2296653
  • 1,151
  • 1
  • 8
  • 17

4 Answers4

2

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.

the_jk
  • 539
  • 2
  • 10
  • This indeed solved the problem. Thank you for your quick, exact and explanatory answer. This makes sense to me now, although it is not clear to me at this point, why the copies are directly thrown away. – user2296653 Apr 19 '13 at 18:14
0

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

Ivaylo Strandjev
  • 69,226
  • 18
  • 123
  • 176
  • Sorry for my obviously unclear construction of the output strings and comparisons. My idea was to identify equality with true and difference with false, instead of constructing the statements to be true. I was aware of what I compared and how. – user2296653 Apr 19 '13 at 18:20
0

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

Community
  • 1
  • 1
Agentlien
  • 4,996
  • 1
  • 16
  • 27
0

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.

fatihk
  • 7,789
  • 1
  • 26
  • 48