好的,我通常默认假设错误在我的代码中,但我所看到的对我来说实际上没有意义。
我有std::vector<DocumentWidget *>
,我希望通过一些相对简单的算法对其进行排序。这就是我所看到的。
代码如下所示:
std::vector<DocumentWidget *> documents = DocumentWidget::allDocuments();
// NOTE(eteran): on my system, I have observed a **consistent** crash
// when documents.size() == 17 while using std::sort.
std::sort(documents.begin(), documents.end(), [](const DocumentWidget *a, const DocumentWidget *b) {
int rc = (a->filenameSet_ == b->filenameSet_) ? 0 : a->filenameSet_ && !b->filenameSet_ ? 1 : -1;
if (rc != 0) {
return rc < 0;
}
if(a->filename_ < b->filename_) {
return true;
}
return a->path_ < b->path_;
});
看起来很简单,但是当我在列表中有第17个项目时它会崩溃!排序谓词显然没有以任何方式修改vector
,所以我看不出这是一个问题。地址清理器和valgrind在此之前没有显示任何错误。
qSort
不会崩溃,似乎工作正常。没有其他正在运行的线程正在接触这些数据,无论我走得多慢,它都会可靠地发生......所以这不是竞争条件。
当我查看调试器时,a
参数似乎是“一个结束”迭代器所指向的位置。但如果std::sort
行为,则不应该发生这种情况。
注意 std::vector
中有17个项目,我强制调试器显示第18个项目,以说明a
似乎来自哪里。
我无法想象std::sort
被窃听,但我真的很难找到另一种解释。我在这里错过了一些明显的错误吗?!
答案 0 :(得分:15)
if(a->filename_ < b->filename_) {
return true;
}
return a->path_ < b->path_;
这被称为“不是有效的严格弱排序”:
{ "a", "d" } < { "b", "c"}; because "a" < "b"
{ "b", "c" } < { "a", "d"}; because "c" < "d"
修复很简单:不要重新发明轮子:
return std::tie(a->filename_, a->path_) < std::tie(b->filename_, b->path_);
答案 1 :(得分:1)
@ T.C。答案是一个很好的答案,因为这个问题被标记为C ++ 11,但是如果未来的读者正在使用C ++ 03解决方案,那么“规范”#c编写这样一个比较运算符的方法(对于成员m1,m2,...... mn)是
if (a->m1 != b-m1)
return a->m1 < b->m1;
else if (a->m2 != b->m2)
return a0>m2 < b->m2;
else ...
else if (a->mn != b->mn)
return a->mn < b->mn;
else
return false;
(请参阅here进行讨论,问题具有上述风格,但避免使用操作员!=)。
还有一件事是你使用指针而你的代码不是防弹的。如果a
或b
为NULL,则会发生崩溃。如果你不能避免指针而你想要偏执,那么你需要添加像
if (!a && !b)
return false;
else if (!a)
return true;
else if (!b)
return false;