问题描述
大家好,我刚开始学习C++,学习教材是C++ Primer 第五版。今天在完成书上的一个练习时(324页,练习9.43),总是发生out_of_range错误,经过调试发现,函数find_and_replace中的for循环没有终止。
代码如下:
#include <iostream>#include <string>int find_and_replace(std::string& org_str, const std::string& str4find, const std::string& str4replace);int main(int argc, char const *argv[]){ std::string str('I am a very loooooong string to be process!'); int find_times; find_times = find_and_replace(str, 'a', '###'); std::cout << find_times << std::endl; std::cout << str << std::endl; return 0;}int find_and_replace(std::string& org_str, const std::string& str4find, const std::string& str4replace){ int find_times = 0; // 被检查字符串长度小于等于匹配字符串长度的情况 if (org_str.size() < str4find.size()) {std::cout << 'Error: The original string is too short!' << std::endl;return find_times; } else if (org_str == str4find) {org_str.assign(str4replace);++find_times;return find_times; } // 其他情况 for (auto i = org_str.begin(), j = i + str4find.size(); j != org_str.end(); ) {std::string temp(i, j);std::cout << temp << std::endl;if (temp == str4find){ j = org_str.erase(i, j); org_str.insert(i, str4replace.begin(), str4replace.end()); std::cout << org_str << std::endl; std::cout << *i << std::endl; j = i + str4find.size(); std::cout << *j << std::endl; ++find_times;}else{ ++i; ++j;} } // 跳出循环时,迭代器i和org_str.end()中间的字符串还没有检查 if (org_str.substr(org_str.size() - str4find.size()) == str4find) {org_str.erase(org_str.size() - str4find.size(), str4find.size());org_str.insert(org_str.end(), str4replace.begin(), str4replace.end());++find_times; } return find_times;}
我在擦除和插入操作后都及时更新了迭代器j而且能够保证i始终在j之前,请问为什么我的循环终止条件j != org_str.end()没有起作用呢?
问题解答
回答1:你既然知道erase之后用返回值提供的迭代器,那么insert同样有可能会让迭代器失效,而且你的这种替换方法逻辑有问题,如果'a',替换成'abc',你这个就无限替换了。。。
回答2:你遍历的时候去改变这个string, 很可能迭代器已经失效了. 你看看是不是这个问题
回答3:现在这个问题我搞明白了,算是自问自答吧,正如上面两位朋友所言,问题出在擦除和插入数据后i和j是失效的迭代器,尽管std::cout输出的看上去正确,但是其本质上还是失效的。由于我的编译器不支持i = org_str.insert(i, str4replace.begin(), str4replace.end());因此我只好写了一个循环,新版的更正后的代码如下:
#include <iostream>#include <string>int find_and_replace(std::string& org_str, const std::string& str4find, const std::string& str4replace);int main(int argc, char const *argv[]){ std::string str('I am a very loooooong string to be process!'); int find_times; find_times = find_and_replace(str, 'o', '!@#'); std::cout << find_times << std::endl; std::cout << str << std::endl; return 0;}int find_and_replace(std::string& org_str, const std::string& str4find, const std::string& str4replace){ int find_times = 0; // 被检查字符串长度小于等于匹配字符串长度的情况 if (org_str.size() < str4find.size()) {std::cout << 'Error: The original string is too short!' << std::endl;return find_times; } else if (org_str == str4find) {org_str.assign(str4replace);return ++find_times; } // 其他情况 // 终止条件是为了保证最后一段能够处理完毕,如果按照之前的j != org_str.end(),则还需要在循环外写一段代码处理最后一段字符串 for (auto i = org_str.begin(), j = i + str4find.size(); (i + (str4find.size() - 1)) != org_str.end(); ) {std::string temp(i, j);// std::cout << temp << std::endl;if (temp == str4find){ // 更新i i = org_str.erase(i, j); for (auto k = str4replace.begin(); k != str4replace.end(); ++k, ++i) {// 每次都更新ii = org_str.insert(i, *k); } // 用i更新j j = i + str4find.size(); ++find_times;}else{ ++i; ++j;} } return find_times;}