c++ - 在字符串中使用删除函数是否会使迭代器无效

标签 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--);

    }
}

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

最佳答案

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

C++ 允许字符串迭代器立即失效。

C++ 标准传统上对 std::string 的要求更加灵活。 (或者,换句话说,它传统上允许实现者使用对 vector 无效的优化。)std::string::erase 和其他字符串修改器也是如此。

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

  1. 引用 basic_string 序列元素的引用、指针和迭代器可能会因以下对该 basic_string 对象的使用而失效:
    • 作为对非常量 basic_string 的引用作为参数的任何标准库函数的参数。
    • 调用非常量成员函数,operator[]atfrontbackbeginrbeginendrend

换句话说,调用像 std::string::erase 这样的潜在变异函数可能会使该字符串的所有迭代器无效,即使没有对该字符串进行可见的修改也是如此 em>(例如,因为要删除的范围是空的)。

(最新的 C++ 标准草案具有相同的措辞,尽管现在是第 4 段。)

如果字符串的第一个字符不是字母,建议的代码涉及未定义的行为。

在字符串的第一个循环中,迭代器 it 的值为 str.begin()。该迭代器不能递减,因为结果不会在字符串内。因此,递增递减的迭代器可能不会将 it 返回给 str.begin() 以进行下一次迭代。

使用索引而不是迭代器

以上均不适用于整数位置索引。因此,如果您可以安全地用非常相似的循环替换您的循环:

void removeNonAlpha(string& str){
    for (auto sz = str.size(), i = 0; i < sz; ++i){
        if (!(isUpperCaseLetter(str[i]) ||
              isLowerCaseLetter(str[i]) ||
              str[i] == ' '))  
            str.erase(i--);
    }
}

关于c++ - 在字符串中使用删除函数是否会使迭代器无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28226836/

相关文章:

javascript - 如何使用 Javascript 从推文中提取 Twitter 用户名

c++ - 实现昂贵的 C++ 迭代器

java - 带有列表迭代器的 ClassCastException Java

c++ - 通过 boost regex 替换行与相对复杂的 regex 的 boost

c++ - 为什么重载继承的静态函数不明确?

python - 反转 Python 字符串的切片

c++ - 保理技术找到类似的方法?

c++ - 如何在最后一个 EOL 后删除文件内容?

c++ - ->、->* 和 .* 运算符的正确术语是什么?

c++ - 字符串 vector ,每个字符串的长度和 C++ 中的 strlen