使用空格填充字符串有时会破坏字符串迭代器

时间:2014-11-26 15:12:42

标签: c++ string iterator whitespace padding

我有这个谓词函数,它按字母顺序比较两个字符串,被比较的字符串是人名,因此长度不等,为了得到这个,较短的字符串用空格填充。

问题:

Error

我已将错误跟踪到字符串填充...这似乎随机破坏了字符串迭代器:

ls += std::string(  maxlen - ls.size(), ' '  ) ;
rs += std::string(  maxlen - rs.size(), ' '  ) ;

这是成功填充后两个字符串迭代器的样子,因为你可以看到它们都指向它们各自的字符串: healthy string iters

&安培;这里是比较名称列表中相同的字符串迭代器,因为你可以看到riter现在指向'ar5'而不是“Aaron Tasso”,我猜这是导致错误的原因: unhealth string iter

我尝试从输入中删除“Abraham Possinger”这个名字,但它在另一个名字的列表中引发了相同的错误。

输入:

Aaron Tasso               
Aaron Tier                 
Abbey Wren                 
Abbie Rubloff              
Abby Tomopoulos           
Abdul Veith               
Abe Lamkin                  
Abel Kepley              
Abigail Stocker            
Abraham Possinger  
bool 
alphanum_string_compare( const std::string& s, const std::string& s2 )
#pragma region CODE
{

  // copy strings: ...for padding to equal length..if required?
  std::string ls = s ;
  std::string rs = s2 ;

// string iters
std::string::const_iterator liter = ls.begin() ;
std::string::const_iterator riter = rs.begin() ;

  // find length of longest string
  std::string::size_type maxlen = 0 ;
  maxlen = std::max( ls.size(), rs.size() ) ;  

// pad shorter of the 2 strings by attempting to pad both ;) 
// ..only shorter string will be padded!..as the other string == maxlen
// ..possibly more efficient than finding and padding ONLY the shorter string
ls += std::string(  maxlen - ls.size(), ' '  ) ;
rs += std::string(  maxlen - rs.size(), ' '  ) ;



  // init alphabet order map
  static std::map<char, int> m = alphabet() ;
  //std::map<char, int> m = alphabet();



  while(  liter != ls.end() && riter != rs.end()  ) 
  {
    if ( m[ *liter ] < m[ *riter ]  ) return true ;
    if ( m[ *liter ] > m[ *riter ]  ) return false ;

    // move to next char
    ++liter ;
    ++riter ;
  }




    return false ;

}
#pragma endregion CODE

4 个答案:

答案 0 :(得分:3)

问题是你在分配迭代器后填充字符串

// string iters
std::string::const_iterator liter = ls.begin() ;
std::string::const_iterator riter = rs.begin() ;

ls += std::string(  maxlen - ls.size(), ' '  ) ; <----------- potentially invalidates iterator
rs += std::string(  maxlen - rs.size(), ' '  ) ; <----------- potentially invalidates iterator

  while(  liter != ls.end() && riter != rs.end()  ) { <--- using invalid iterator
    if ( m[ *liter ] < m[ *riter ]  ) return true ;
    if ( m[ *liter ] > m[ *riter ]  ) return false ;

    // move to next char
    ++liter ;
    ++riter ;
  }

    return false ;    
}

如果您在已结束的循环之后检查并在那里返回正确的true或false值,则不需要填充。

答案 1 :(得分:2)

std::string是一个动态对象,当你修改它时,很可能会重新分配它的内部内存缓冲区。此时,您的“旧”迭代器指向返回堆(已删除)的内存。它与大多数容器一样,例如std::vector - 您可以将迭代器复制到任意元素,但是一旦向向量添加任何内容,迭代器可能就不再有效了。 任何大多数“修改”操作使这些对象的迭代器无效。

答案 2 :(得分:2)

当在扩展时重新分配底层存储时,填充可能使迭代器无效。

可以通过填充后检索迭代器解决这个问题,但填充是不必要的。

你只需要检查迭代器结束的位置 - 如果迭代器到达结尾但s小于s2但另一个没有结束。

bool 
alphanum_string_compare( const std::string& s, const std::string& s2 )
{
    static std::map<char, int> m = alphabet();

    std::string::const_iterator left = s.begin();
    std::string::const_iterator right = s2.begin();

    while (left != s.end() && right != s2.end()) 
    {
        if (m[*left] < m[*right])
            return true;
        if (m[*left] > m[*right])
            return false;
        ++left;
        ++right;
    }
    return left == s.end() && right != s2.end();
}

答案 3 :(得分:1)

如果您只是按字母顺序查看哪个名称首先出现,我认为不需要填充空格。一个想法可能是:每次在循环周围检查哪个字符最小,如果一个字符小于另一个字符,则返回该字符串。例如:

string StrCompare(const string& s1, const string& s2)
{
  string::size_type len = (s1.length() < s2.length() ? s1.length() : s2.length());

  for (auto i = 0; i != len; ++i) {
    if (s1[i] < s2[i])
      return s1;
    else if (s2[i] < s1[i])
      return s2;
    else
      ;// do nothing
  }
}

main()的

string str = StrCompare("Aaron Tasso", "Aaron Tier");
cout << str;

输出:Aaron Tasso