简体   繁体   中英

Error using operator != with std::vector iterator

In some legacy code I see the following:

class myClass : public CObject
{
    DECLARE_DYNAMIC(myClass)

public:
    void myClassMethod() const;
    ....
}
std::vector<const myClass*> vMyClass;
...
for (const myClass *const* Q = vMyClass.begin(); Q != vMyClass.end(); Q++)
        (*Q)->myClassMethod();

I don't understand what const is doing here. (I can't search for it, either in this forum or in Google, without the asterisks being stripped off, so searching for an explanation is useless.)

What I do know is that this code generally assumed that vector.begin() returns a pointer rather than an iterator. So I tried rewriting the for loop as:

std::vector<myClass*>::iterator Q;

for (Q = vMyClass.begin(); Q != vMyClass.end(); Q++)
    (*Q)->myClassMethod();

But I get the following error from the Visual Studio 2003 C++ compiler:

error C2678: binary '!=' : no operator found which takes a left-hand operand of type 'std::vector<_Ty>::iterator' (or there is no acceptable conversion) with [ _Ty=myClass * ]

I don't understand what's going wrong here... In another part of the code I have:

std::vector<myOtherClass> vMyOtherClass;
...
std::vector<myOtherClass>::iterator Z;

for (Z = vMyOtherClass.begin(); Z != vMyOtherClass.end(); ++Z)
    ...

this compiles cleanly. Any ideas why I get the error on the vMyClass loop or what to do about it? Any idea what const is doing?

New Information

Originally, I had copied the vector definition incorrectly. Now that it's fixed (above), I see that the iterator was missing a const. It should read:

std::vector<const myClass*>::iterator Q;

But when I made this fix in my code, the error message switched from the call to vector.end() to vector.begin():

error C2679: binary '=' : no operator found which takes a right-hand operand of type 'std::vector<_Ty>::const_iterator' (or there is no acceptable conversion) with [ _Ty=const myClass * ]

I don't get how it could work for vector.end() with operator !=, yet be wrong for vector.begin() with operator =...?

I don't understand what const is doing here.

const applies to the thing on its left, unless nothing is there, then it applies to the thing on its right instead.

Remember that whitespace doesn't matter, so let's make your declaration a little easier to read:

const myClass * const * Q

Which is the same as

const myClass* const *Q

The first const applies to myClass , and the second const applies to the first * .

Declarations are read in right-to-left order (see Easy rule to read complicated const declarations? ), so this declaration basically says:

"Q is a non-const pointer to a const pointer to a const MyClass object"

Basically, meaning that the value of Q itself can be changed (good for iterating), but the value of the myClass* pointer that Q is pointing at can't be changed, and the myClass object that is being pointed at by the myClass* pointer can't be changed either (only const methods can be called on it).

Below example will clear your doubt regarding const myClass *const* Q :

#include <iostream>
using namespace std;

int main(void)
{
    int i = 10;
    int j = 20;
    int *pt = &j;

    /* constant pointer to constant integer */
    const int *const ptr = &i;  

    /* constant pointer to constant poniter */
    const int *const * pptr = &pt;  

    cout<< " Address of i :" << &i << "    Address of J : " << &j <<endl;
    cout<< " value of i :  " << i << "    value of J : " << j << endl;
    cout<<" pptr :   " << pptr << endl;
    cout<<" ptr  :   " << ptr << endl;  // ptr is point to i
    cout<<" *pptr :   " << *pptr << endl; // *pptr is pointing j
    cout<<" *ptr  :   " << *ptr << endl;
    cout<<" **pptr :   " << (*(*pptr)) << endl;

    return 0;
}

Output ::

Address of i :0x22fe3c    Address of J : 0x22fe38
value of i :  10    value of J : 20
pptr :   0x22fe30
ptr  :   0x22fe3c
*pptr :   0x22fe38
*ptr  :   10
**pptr :   20

Hope you are clear now.

What I do know is that this code generally assumed that vector.begin() returns a pointer rather than an iterator

You are wrong here, it returns an iterator. Please refer to vector::begin() reference .

(check your myClassMethod function ( (*Q)->myClassMethod(); ) ) and refer to error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const Recipe' (or there is no acceptable conversion)

My suggestion : use latest C++11/C++14 feature (Like auto , ...).

You actually have const in two places, with somewhat different effects.

for (const myClass *const* Q = vMyClass.begin(); Q != vMyClass.end(); Q++)
     ^^1^^          ^^2^^

First, let's separate out the declaration from the rest:

const myClass *const* Q

Let's start by making this consistent, and putting each const after what it modifies. In this case, that means moving only the first one:

myClass const *const* Q

For a declaration like this, we want to start from the name of the object being declared, and read "*" as "pointer to a", so this is read as something like this:

 Q is a pointer to a const pointer to a const myClass

The problem you have doesn't really relate to const at all. The problem you have is that the author of the code depended on the fact that in some particular library, std::vector<T>::iterator was (apparently) implemented as a pointer to T. This is allowable, but has some undesirable side effects (eg, it means vector<derived>::iterator can be implicitly converted to vector<base>::iterator ) so modern implementations generally avoid it.

If you want to convert this code to modern C++, all that is sort of beside the point though--you probably want to use something like this:

for (auto Q : vMyClass)
    Q->myClassMethod();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM