std::sort排序小写字符串vector时出现与空字符串比较的疑问
问题复现代码
#include <iostream> #include <vector> #include <string> #include <algorithm> int main(int argc, char const *argv[]) { std::vector<std::string> lst{"cat", "dog", "dogs", "chicken", "chickens", "cats", "dogs"}; std::sort(lst.begin(), lst.end(), [](const auto &lhs, const auto &rhs) { int i = 0; int n = lhs.size(); int m = rhs.size(); std::cout << n << " " << m << std::endl; while(i < n && i < m && lhs.at(i) == rhs.at(i)) { ++i; } if(i == n && i == m) return true; // same exact word else if(i == n || i == m) return lhs.size() < rhs.size(); return lhs.at(i) < rhs.at(i); }); }
问题原因
- 自定义比较函数不符合
std::sort要求的严格弱序约束,触发未定义行为。
严格弱序要求比较函数comp(a,b)必须满足:如果a和b逻辑相等,那么comp(a,b)和comp(b,a)都必须返回false。你代码中当两个字符串完全相等时,返回值为true,直接违反了该约束,会导致std::sort内部逻辑完全错乱。 - 空字符串的来源是被移动后的原列表元素。
std::sort排序过程中会移动元素调整位置,当比较逻辑异常时,可能会访问已经被移动走的std::string对象。C++标准规定被移动后的std::string处于有效但未指定的状态,绝大多数标准库实现都会将被移动后的字符串置为空,这就是你看到长度为0的字符串的原因,并非出现了不在原列表中的新元素。
修复方案
仅需要修改相等场景的返回值即可,相等元素不满足小于关系,返回false:
if(i == n && i == m) return false;
修改后比较函数符合严格弱序要求,未定义行为消失,不会再出现空字符串的异常。
内容的提问来源于stack exchange,提问作者user5965026
相关产品推荐
相关产品推荐

