【问题标题】:Error using operator != with std::vector iterator将运算符 != 与 std::vector 迭代器一起使用时出错
【发布时间】:2018-04-22 20:57:14
【问题描述】:

在一些遗留代码中,我看到以下内容:

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();

我不明白 const 在这里做什么。 (无论是在这个论坛还是在谷歌中,我都无法搜索到它,星号会被去掉,所以搜索解释是没有用的。)

我所知道的是,这段代码通常假设 vector.begin() 返回一个指针而不是迭代器。所以我尝试将for循环重写为:

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

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

但我从 Visual Studio 2003 C++ 编译器收到以下错误:

error C2678: binary '!=' : no operator found which take a left-hand 'std::vector<_ty>::iterator' 类型的操作数(或者没有 可接受的转换)与 [ _Ty=myClass * ]

我不明白这里出了什么问题...在我的另一部分代码中:

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

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

这编译干净。任何想法为什么我会在 vMyClass 循环上收到错误或如何处理它?知道 const 在做什么吗?

新信息

最初,我错误地复制了矢量定义。现在它已经修复(上图),我看到迭代器缺少一个 const。它应该是:

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

但是当我在我的代码中进行此修复时,错误消息从对 vector.end() 的调用切换到 vector.begin():

错误 C2679:二进制“=”:未找到采用右手的运算符 'std::vector<_ty>::const_iterator' 类型的操作数(或者没有 可接受的转换)与 [ _Ty=const myClass * ]

我不明白vector.end() 和operator != 是如何工作的,但是vector.begin() 和operator =... 是错误的?

【问题讨论】:

  • 您似乎需要改用const_iterator,但最好使用auto
  • @Slava in VS 2003 auto 不会编译。
  • @manni66 不知道,谢谢
  • VS 2003 已经过时了。考虑使用 VS 2017!
  • @manni66,你基本上是正确的。实际上自动编译,但它被解释为 int。所以它真的不起作用。请参阅下面关于我们选择 VS 2003 的评论。

标签: c++ vector


【解决方案1】:

我不明白 const 在这里做什么。

const 适用于其左侧的东西,除非那里什么都没有,否则它适用于其右侧的东西。

请记住,空格并不重要,所以让我们让您的声明更易于阅读:

const myClass * const * Q

与

相同
const myClass* const *Q

第一个const 应用于myClass,第二个const 应用于第一个*。

声明按从右到左的顺序阅读(请参阅Easy rule to read complicated const declarations?),所以这个声明基本上是这样说的:

“Q 是一个非常量指针,指向一个指向 const MyClass 对象的 const 指针”

基本上,意思是Q本身的值可以改变(有利于迭代),但是Q指向的myClass*指针的值不能改变,myClass myClass* 指针指向的对象也不能更改(只能在其上调用 const 方法)。

【讨论】:

  • 谢谢 - 你的解释很有帮助。不知道为什么我这个代码的原始开发者必须以如此晦涩的方式编写它......:(
  • @ToddHoatson:可能只是过于谨慎。如果begin() 实际上确实返回了一个指针作为迭代器,那么Q 可以简单地声明为myClass**。但是迭代器是一种抽象,最好不要假设迭代器只使用一个指针来实现(即使这是允许的)。
【解决方案2】:

以下示例将消除您对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;
}

输出 ::

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

希望你现在清楚了。

我所知道的是这段代码通常假设vector.begin()返回一个指针而不是一个迭代器

你错了,它返回一个迭代器。请参阅 vector::begin() reference.

(检查你的myClassMethod函数((*Q)-&gt;myClassMethod();)) 并参考error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const Recipe' (or there is no acceptable conversion)

我的建议:使用最新的 C++11/C++14 功能(如auto,...)。

【讨论】:

  • 我在上面的问题中添加了 myClassMethod() 的声明。它被声明为 const,因此使用“指向 const MyClass 对象的 const 指针的非 const 指针”调用它应该不是问题,对吧?此外,旧代码在 Visual C++ 6.0 中干净地编译。直接跳到 C++11/14 将是太大的一步。最好先迈出 VS 2003 的中间步骤……
  • @ToddHoatson: 是的,你可以通过const myClass* 指针调用const 方法(如myClassMethod())(事实上,这就是你可以调用的全部)
  • 所以@RemyLebeau,有什么想法为什么我使用 !=... 会收到此错误?
  • 错误信息显示!=左侧的迭代器变量使用CQueryThing*而不是myClass*。您是否重命名了问题中的类型,还是您的真实代码中存在合法的不匹配?
  • 抱歉,为了清楚起见,重命名了代码中的内容,但忘记编辑错误消息...我在上面的问题中更改了它。
【解决方案3】:

实际上,const 在 两个 处,但效果略有不同。

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

首先,让我们将声明与其他声明分开:

const myClass *const* Q

让我们首先保持一致,并将每个 const 放在它修改的内容之后。在这种情况下,这意味着只移动第一个:

myClass const *const* Q

对于这样的声明,我们希望从被声明的对象的名称开始,并将“*”读作“指向a的指针”,因此读作如下:

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

您遇到的问题根本与const 无关。您遇到的问题是代码的作者取决于这样一个事实,即在某些特定库中,std::vector&lt;T&gt;::iterator (显然)被实现为指向 T 的指针。这是允许的,但有一些不良副作用(例如,这意味着vector&lt;derived&gt;::iterator 可以隐式转换为 vector&lt;base&gt;::iterator),因此现代实现通常会避免它。

如果您想将此代码转换为现代 C++,那么所有这些都不是重点——您可能希望使用如下代码:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-12
    • 2011-04-12
    • 1970-01-01
    • 2012-05-07
    • 2020-08-20
    • 2011-02-01
    • 2013-02-08
    • 2012-05-02
    相关资源
    最近更新 更多