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



我在以下代码上使用迭代器时遇到问题? 有谁知道如何解决它?

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;
}

错误信息: 没有可行的转换从

'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)) {

谢谢你的帮助。

看看你调用的函数:

wordcount_map.count(iter)
^^^^^

现在,看一下参数的类型:

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

请注意,该参数应是映射的键。现在,看看映射的密钥类型:

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

这是一个字符串。最后,看看你尝试传递给函数的参数的类型:

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

你能看出问题吗?您正在将迭代器传递到需要字符串的函数中。这是一个完全错误的对象类型,甚至不能转换为预期的类型。这就是您收到错误的原因:

错误消息:没有从 [迭代器] 到 [字符串] 的可行转换


你还没有描述你要做什么,但考虑到迭代器指向一个字符串,而你调用的函数需要一个字符串,我猜你想将迭代器指向的字符串传递到函数中。要访问指向的字符串,您需要通过迭代器间接访问。这可以使用间接寻址运算符来实现:

*iter
<小时 />

附言如果进入循环,它将永远不会结束(除非某些内容被抛出或进程被终止),因为iter永远不会被修改,因此无法更改结束条件。

此外,else分支似乎总是抛出(这将结束循环)。

假设你想使用iter当前引用words向量的std::string元素作为wordcount_map中的索引/键,那么你只需要用*运算符取消引用iter。此外,就目前而言,您的while循环不会对iter变量进行任何修改;在循环结束时,您可能需要一个增量 (++) 运算符:

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;
}

但是,与其将++iter添加为while循环中的单独行,不如改用for循环:

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

或者,更简单的是,根本不使用显式迭代器;只需使用"基于范围"的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;
}
}

正如其他答案所解释的那样,您会收到编译器错误,因为您没有取消引用迭代器以访问它所引用的std::string

我只想补充一点,即使修复了该错误,您的代码仍然存在逻辑错误:

  • 您的循环根本不会递增迭代器,因此如果words向量不为空,它将无休止地运行。

  • 您的循环体是向后实现的。std::unordered_map::count()返回与请求的键匹配的元素if语句将数值 0 视为false,将任何其他数值视为true。因此,如果count()返回> 0指示给定键确实存在,则使用值 1更新该元素,擦除其先前的值。 如果count()返回0指示给定键不存在,则使用相同的键调用std::unordered_map::at(),这将失败并引发std::out_of_range异常。

更正后的版本如下所示:

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;
}

但是,此代码不必要地复杂且效率低下。可以大大简化为:

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;
}

基于范围的for循环将为您处理迭代器。std::unordered_map::operator[]返回对元素值的引用,如果请求的键尚不存在,则为您插入和初始化一个新元素。

错误不在你认为的行中。在代码之后和其余代码的行中,您忘记取消引用iter,并在需要std::string的地方传递迭代器。修复:

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

最新更新