我在以下代码上使用迭代器时遇到问题? 有谁知道如何解决它?
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;
}