在c++ 11基于范围的for循环中,通过迭代器删除字符串中的空白

Deleting whitespace from a string via an iterator to the string in a C++11 range-based for loop

本文关键字:c++ 迭代器 空白 字符串 删除 循环 for 于范围 范围      更新时间:2023-10-16

我只是想用c++ 11的基于范围的for循环删除字符串中的所有空白;然而,我总是在basic_string::erase上得到std::out_of_range

#include <iostream>
#include <string>
#include <typeinfo>
int main(){
  std::string str{"hello my name is sam"};
  //compiles, but throws an out_of_range exception
  for(auto i : str){
    std::cout << typeid(i).name();  //gcc outputs 'c' for 'char'
    if(isspace(i)){
      str.erase(i);
    }
  }
  std::cout << std::endl;
  //does not compile - "invalid type argument of unary '*' (have 'char')"
  for(auto i : str){
    if(isspace(*i)){
      str.erase(i);
    }
  }
  //works exactly as expected
  for(std::string::iterator i = begin(str); i != end(str); ++i){
    std::cout << typeid(*i).name();  //gcc outputs 'c' for 'char'
    if(isspace(*i)){
      str.erase(i);
    }
  }
  std::cout << std::endl;
}

所以我想知道:前两个循环中的i到底是什么?为什么它似乎都是char(如typeid所验证)和iteratorchar(与std::string::erase一起工作)?为什么它不等同于最后一个循环中的iterator ?在我看来,它们的功能应该完全相同。

在基于范围的for循环中,i的类型是char,因为字符串的元素是字符(更正式地说,std::string::value_typechar的别名)。

传递给erase()时,看起来像是作为迭代器工作的原因是存在erase()的重载,它接受索引和计数,但后者有一个默认参数:
basic_string& erase( size_type index = 0, size_type count = npos );

在您的实现中,char恰好可以隐式转换为std::string::size_type。然而,这很可能是不是做您所期望的。

要验证i确实不是一个迭代器,试着解引用它,你会看到编译器尖叫:

*i; // This will cause an error