简体   繁体   English

如何在 C++ 中实现迭代器?

[英]How to implement the iterator in C++?

I have a problem with using iterator on the following code?我在以下代码上使用迭代器时遇到问题? Does anyone know how to fix it?有谁知道如何修理它?

using StringVec = std::vector<std::string>;
using StringIntMap = std::unordered_map<std::string, int>;
  
StringIntMap makeWordCounts(const StringVec& words) {
   StringIntMap wordcount_map;
    
    std::vector<std::string>::const_iterator iter = words.begin();
    while(iter != words.end()) { //error message appears here
        if(wordcount_map.count(iter)) {
            wordcount_map[iter] = 1;
        }else{
            int value = wordcount_map.at(iter);
            wordcount_map[iter] = value+1;
        }
    }
  return wordcount_map;
}

error message: no viable conversion from错误消息:没有可行的转换来自

 'std::vector<std::string>::const_iterator' (aka '__wrap_iter<const
  std::__1::basic_string<char> *>') to 'const
  std::__1::unordered_map<std::__1::basic_string<char>, int,
  std::__1::hash<std::__1::basic_string<char> >,
  std::__1::equal_to<std::__1::basic_string<char> >,
  std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>,
  int> > >::key_type' (aka 'const std::__1::basic_string<char>')
    if(wordcount_map.count(iter)) {

Thank you for your help.感谢您的帮助。

Take a look at what function you're calling:看看你调用的是什么函数:

 wordcount_map.count(iter) ^^^^^

Now, take a look at the type of the parameter:现在,看一下参数的类型:

size_type count( const Key& key ) const;
                 ^^^^^^^^^^

Notice that the parameter is expected to be a key of the map.请注意,该参数应该是地图的键。 Now, take a look at the key type of you map:现在,看看你映射的键类型:

 using StringIntMap = std::unordered_map<std::string, int>; ^^^^^^^^^^^

It is a string.它是一个字符串。 And finally, take a look at the type of the argument that you attempt to pass into the function:最后,看看你试图传递给函数的参数的类型:

 std::vector<std::string>::const_iterator iter = words.begin(); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Can you see the problem?你能看出问题吗? You are passing an iterator into a function that expects a string.您正在将迭代器传递给需要字符串的函数。 That is an entirely wrong type of object, and not even convertible to the expected type.这是一种完全错误的对象类型,甚至不能转换为预期的类型。 That is why you get the error:这就是您收到错误的原因:

error message: no viable conversion from [iterator] to [string]错误消息:没有从 [iterator] 到 [string] 的可行转换


You haven't described what you're trying to do, but given that the iterator points to a string, and the function that you call expects a string, I would guess that you want to pass the string pointed by the iterator into the function.您还没有描述您要做什么,但鉴于迭代器指向一个字符串,而您调用的函数需要一个字符串,我猜您想将迭代器指向的字符串传递给函数. To access the pointed string, you need to indirect through the iterator.要访问指向的字符串,您需要通过迭代器间接访问。 This can be achieved using the indirection operator:这可以使用间接运算符来实现:

*iter

PS If the loop is entered, it will never end (except if something is thrown out of it or process is terminated) because iter is never modified and thus there cannot be change to the end condition. PS 如果进入循环,它将永远不会结束(除非有东西被抛出或进程终止),因为iter永远不会被修改,因此不会改变结束条件。

Also, the else branch seems to always throw (which would end the loop).此外, else分支似乎总是抛出(这将结束循环)。

Assuming you want to use the std::string element of the words vector that iter currently references as your index/key in wordcount_map , then you simply need to dereference iter with the * operator.假设您想使用iter当前引用words向量的std::string元素作为wordcount_map索引/键,那么您只需要使用*运算符取消引用iter Also, as it stands, your while loop doesn't make any modification to the iter variable;此外,就目前而言,您的while循环不会对iter变量进行任何修改; you probably need an increment ( ++ ) operator on it at the end of the loop:在循环结束时,您可能需要一个增量 ( ++ ) 运算符:

using StringVec = std::vector<std::string>;
using StringIntMap = std::unordered_map<std::string, int>;

StringIntMap makeWordCounts(const StringVec& words)
{
    StringIntMap wordcount_map;

    std::vector<std::string>::const_iterator iter = words.begin();
    while (iter != words.end()) {
        if (wordcount_map.count(*iter)) { // Use * to dereference iter
            wordcount_map[*iter] = 1;     // ... and here
        }
        else {
            int value = wordcount_map.at(*iter); // ...
            wordcount_map[*iter] = value + 1;    // ...
        }
        ++iter; // Increment the iterator to move on to the next vector element
    }
    return wordcount_map;
}

However, rather than adding ++iter as a separate line in a while loop, you could just use a for loop instead:但是,与其在while循环中将++iter添加为单独的行,不如使用for循环:

    for (std::vector<std::string>::const_iterator iter = words.begin(); iter != words.end(); ++iter) {
        //...

Or, even simpler, don't use an explicit iterator at all;或者,更简单的是,根本不使用显式迭代器; just use a 'range-based' for loop:只需使用“基于范围”的for循环:

    for (auto str : words) {
        if (wordcount_map.count(str)) {
            wordcount_map[str] = 1;
        }
        else {
            int value = wordcount_map.at(str);
            wordcount_map[str] = value + 1;
        }
    }

As other answers have explained, you are getting the compiler error because you are not dereferencing the iterator to access the std::string it is referring to.正如其他答案所解释的那样,您收到编译器错误是因为您没有取消引用迭代器来访问它所引用的std::string

I just want to add that even with that error fixed, your code still has logic mistakes in it:我只想补充一点,即使修复了该错误,您的代码中仍然存在逻辑错误:

  • your loop is not incrementing the iterator at all, so it will run endlessly if the words vector is not empty.您的循环根本不会增加迭代器,因此如果words向量不为空,它将无休止地运行。

  • your loop body is implemented backwards.你的循环体是向后实现的。 std::unordered_map::count() returns the number of elements that match the requested key. std::unordered_map::count()返回与请求的键匹配的元素 An if statement treats a numeric value of 0 as false , and any other numeric value as true . if语句将数值 0 视为false ,将任何其他数值视为true So, if count() returns > 0 indicating a given key does exist, you are updating that element with a value of 1, wiping out its previous value.因此,如果count()返回> 0表示给定的键确实存在,则您正在使用值 1更新该元素,并删除其先前的值。 And if count() returns 0 indicating a given key does not exist, you are calling std::unordered_map::at() with that same key, which fails and throws a std::out_of_range exception.如果count()返回0表示给定的键存在,则您正在使用相同的键调用std::unordered_map::at() ,该键失败并抛出std::out_of_range异常。

The corrected version would look like this:更正后的版本如下所示:

using StringVec = std::vector<std::string>;
using StringIntMap = std::unordered_map<std::string, int>;
  
StringIntMap makeWordCounts(const StringVec& words) {
   StringIntMap wordcount_map;
    
    StringVec::const_iterator iter = words.begin();
    while (iter != words.end()) {
        if (wordcount_map.count(*iter)) {
            int value = wordcount_map.at(*iter);
            wordcount_map[*iter] = value + 1;
        }else{
            wordcount_map[*iter] = 1;
        }
        ++iter;
    }

    return wordcount_map;
}

However, this code needlessly complicated and inefficient.然而,这段代码不必要地复杂和低效。 It can be greatly simplified to this:它可以大大简化为:

using StringVec = std::vector<std::string>;
using StringIntMap = std::unordered_map<std::string, int>;
  
StringIntMap makeWordCounts(const StringVec& words) {
    StringIntMap wordcount_map;
    
    for(const auto &word : words) {
        wordcount_map[word]++;
    }

    return wordcount_map;
}

A range-based for loop will handle iterators for you.基于范围的for循环将为您处理迭代器。 And std::unordered_map::operator[] returns a reference to an element's value, inserting and initializing a new element for you if the requested key does not exist yet.并且std::unordered_map::operator[]返回对元素值的引用,如果请求的键尚不存在,则为您插入和初始化一个新元素。

The error is not in the line you think it is.错误不在你认为的那一行。 In the line after and for the rest of the code you forgot to dereference iter and you pass an iterator where a std::string is needed.在后面和其余代码的行中,您忘记取消对iter引用,并且在需要std::string地方传递了一个迭代器。 Fix:使固定:

    if(wordcount_map.count(*iter)) {
        wordcount_map[*iter] = 1;
    }else{
        int value = wordcount_map.at(*iter);
        wordcount_map[*iter] = value+1;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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