在字符串中使用擦除函数是否会使迭代器无效
Does using the erase function in a string invalidate iterators
我有以下代码,它接受一个字符串并删除非字母字符
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
的要求。 (或者,换句话说,它传统上允许实现者使用对向量无效的优化。)std::string::erase
和其他字符串修改器也是如此。
在 [string.require]
(n3797 的第 21.4.1 节)中,标准接受:
- 引用
basic_string
序列元素的引用、指针和迭代器可能会因以下对该 basic_string
对象的使用而失效:
- 作为对非常量
basic_string
的引用作为参数的任何标准库函数的参数。
- 调用非常量成员函数,除了
operator[]
、at
、front
、back
、begin
、rbegin
、end
和 rend
.
换句话说,调用像 std::string::erase
这样的潜在变异函数可能会使该字符串的所有迭代器无效,即使没有对字符串进行可见修改(对于例如,因为要擦除的范围是空的)。
(最新的 C++ 标准草案有相同的措辞,尽管现在是第 4 段。)
如果字符串的第一个字符不是字母,建议的代码涉及未定义的行为。
在字符串的第一次循环中,迭代器 it
的值为 str.begin()
。该迭代器不能递减,因为结果不会在字符串内。因此,在下一次迭代中递增递减迭代器可能不会 return it
到 str.begin()
。
使用索引而不是迭代器
None 以上适用于整数位置索引。所以如果你能安全地用非常相似的循环替换你的循环:
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--);
}
}
我有以下代码,它接受一个字符串并删除非字母字符
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
的要求。 (或者,换句话说,它传统上允许实现者使用对向量无效的优化。)std::string::erase
和其他字符串修改器也是如此。
在 [string.require]
(n3797 的第 21.4.1 节)中,标准接受:
- 引用
basic_string
序列元素的引用、指针和迭代器可能会因以下对该basic_string
对象的使用而失效:- 作为对非常量
basic_string
的引用作为参数的任何标准库函数的参数。 - 调用非常量成员函数,除了
operator[]
、at
、front
、back
、begin
、rbegin
、end
和rend
.
- 作为对非常量
换句话说,调用像 std::string::erase
这样的潜在变异函数可能会使该字符串的所有迭代器无效,即使没有对字符串进行可见修改(对于例如,因为要擦除的范围是空的)。
(最新的 C++ 标准草案有相同的措辞,尽管现在是第 4 段。)
如果字符串的第一个字符不是字母,建议的代码涉及未定义的行为。
在字符串的第一次循环中,迭代器 it
的值为 str.begin()
。该迭代器不能递减,因为结果不会在字符串内。因此,在下一次迭代中递增递减迭代器可能不会 return it
到 str.begin()
。
使用索引而不是迭代器
None 以上适用于整数位置索引。所以如果你能安全地用非常相似的循环替换你的循环:
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--);
}
}