在字符串中使用erase函数是否会使迭代器失效

时间:2015-01-29 23:47:26

标签: c++ string iterator erase invalidation

我有以下代码,它接受一个字符串并删除非字母字符

void removeNonAlpha(string& str){
    for (string::iterator it = str.begin(); it < str.end(); it++){
        if (!(isUpperCaseLetter(*it) || isLowerCaseLetter(*it) || str == ' '))  
            str.erase(it--);

    }
}

我向我的教授展示了这一点,他告诉我这样做有风险,因为它可能使我正在使用的迭代器无效。但是,我认为擦除只会在擦除点之后使迭代器失效,并且我确保在该点之后不使用任何迭代器。 那么这段代码会崩溃还是导致任何未定义的行为?

2 个答案:

答案 0 :(得分:1)

std::vector::erase按照您的建议行事;它只会使从第一个擦除元素开始的迭代器失效。但是,这不适用于std::string

C ++允许字符串迭代器在下降时失效。

传统上,C ++标准对std::string的要求更加灵活。 (或者,换句话说,它传统上允许实现者使用对向量无效的优化。)因此它与std::string::erase以及其他字符串变换器一起使用。

[string.require](n3797的第21.4.1节)中,该标准接受:

  1. 引用basic_string序列元素的引用,指针和迭代器可能会被basic_string对象的以下用法无效:
    • 作为任何标准库函数的参数,将非const basic_string作为参数引用。
    • 调用非const成员函数,operator[]atfrontbackbeginrbegin,{{1除外}和end
  2. 换句话说,调用像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();