我有这个谓词函数,它按字母顺序比较两个字符串,被比较的字符串是人名,因此长度不等,为了得到这个,较短的字符串用空格填充。
问题:
我已将错误跟踪到字符串填充...这似乎随机破坏了字符串迭代器:
ls += std::string( maxlen - ls.size(), ' ' ) ; rs += std::string( maxlen - rs.size(), ' ' ) ;
这是成功填充后两个字符串迭代器的样子,因为你可以看到它们都指向它们各自的字符串:
&安培;这里是比较名称列表中相同的字符串迭代器,因为你可以看到riter现在指向'ar5'而不是“Aaron Tasso”,我猜这是导致错误的原因:
我尝试从输入中删除“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
答案 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