【问题标题】:Deleting whitespace from a string via an iterator to the string in a C++11 range-based for loop通过迭代器从字符串中删除空格到 C++11 基于范围的 for 循环中的字符串
【发布时间】:2013-06-05 23:15:24
【问题描述】:

我只是尝试使用 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?在我看来,它们的功能应该完全相同。

【问题讨论】:

    标签: c++ string c++11 iterator auto


    【解决方案1】:

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

    当您将它传递给erase() 时,它似乎 用作迭代器的原因是存在一个接受索引和计数的overload of erase(),但后者有一个默认参数:

    basic_string& erase( size_type index = 0, size_type count = npos );
    

    在您的实现中,char 恰好可以隐式转换为 std::string::size_type。但是,这可能没有符合您的预期。

    要验证 i 确实不是迭代器,请尝试取消引用它,您会看到编译器尖叫:

    *i; // This will cause an error
    

    【讨论】:

    • 我认为值得注意的是最后给出的for循环可能无法正常工作,因为erase可以使循环迭代器无效。要解决此问题,您可以使用erase 返回的迭代器,尽管如果使用天真,这可能会导致性能下降(循环将是最坏情况的二次而不是线性时间,因为擦除本身是最坏情况的线性)。为了提高效率,您应该使用std::removestd::remove_if,或类似的实现,正如@syam 的回答中所建议的那样(编辑:此后已被删除)。
    • @JohnBartholomew:好点。我的回答主要集中在最后一段的第一个问题上,我没有深入分析:)谢谢您的指出
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-25
    • 2023-03-15
    • 2015-07-04
    • 1970-01-01
    • 2015-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多