我有以下代码,它接受一个字符串并删除非字母字符
void removeNonAlpha(string& str){
for (string::iterator it = str.begin(); it < str.end(); it++){
if (!(isUpperCaseLetter(*it) || isLowerCaseLetter(*it) || str == ' '))
str.erase(it--);
}
}
我向我的教授展示了这一点,他告诉我这样做有风险,因为它可能使我正在使用的迭代器无效。但是,我认为擦除只会在擦除点之后使迭代器失效,并且我确保在该点之后不使用任何迭代器。 那么这段代码会崩溃还是导致任何未定义的行为?
答案 0 :(得分:1)
std::vector::erase
按照您的建议行事;它只会使从第一个擦除元素开始的迭代器失效。但是,这不适用于std::string
。
传统上,C ++标准对std::string
的要求更加灵活。 (或者,换句话说,它传统上允许实现者使用对向量无效的优化。)因此它与std::string::erase
以及其他字符串变换器一起使用。
在[string.require]
(n3797的第21.4.1节)中,该标准接受:
basic_string
序列元素的引用,指针和迭代器可能会被basic_string
对象的以下用法无效:
basic_string
作为参数引用。operator[]
,at
,front
,back
,begin
,rbegin
,{{1除外}和end
。换句话说,调用像rend
这样的潜在变异函数可能会使该字符串的所有迭代器无效,即使没有对字符串进行可见的修改(例如,因为范围要删除的是空的。)
(最新的C ++标准草案具有相同的措辞,尽管它现在是第4段。)
在第一个循环遍历字符串的过程中,迭代器std::string::erase
的值为it
。迭代器不能递减,因为结果不会在字符串内。因此,递增递减的迭代器可能不会将str.begin()
返回到it
以进行下一次迭代。
以上都不适用于整数位置索引。因此,如果你可以安全地用非常相似的方式替换你的循环:
str.begin()
答案 1 :(得分:1)
它不会编译。 str
是std :: string,str == ' '
是两种不同的类型。
其次,当反向迭代时,你需要使用string :: reverse_iterator,string :: rbegin()和string :: rend();