有时,程序在 std::sort() 中崩溃,无法重现

Cha*_*ina 2 c++ crash stl vector

描述:

我的程序有时会崩溃std::sort(),我编写了一个最小的程序来重现这种情况,但一切都很好。这是最小的例子:

typedef struct st {
    int it;
    char ch;
    char charr[100];
    vector<string *> *vs;
} st;

bool function(st *&s1, st *&s2) {
    static int i = 1;
    cout<<i<<" "<<&s1<<" "<<&s2<<endl;
    ++i;
    return s1->it > s2->it;
}

int main(int argc, char **argv) {
    vector<st *> ar;
    for (int i = 0; i < 100; ++i) {
        st *s = new st;
        s->it = urandom32();
        ar.push_back(s);
    }

    ar.clear();

    for (int i = 0; i < 100; ++i) {
        st *s = new st;
        s->it = urandom32();
        ar.push_back(s);
    }

    sort(ar.begin(), ar.end(), function);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是 GDB 堆栈信息:

  • 0 0x00007f24244d9602 在article_cmp (cand_article_1=0x7f23fd297010、cand_article_2=0x4015 ) 位于 src/recom_frame_worker.h:47
  • 1 0x00007f24244fc41b 在 std::__unguarded_pa​​rtition<__gnu_cxx::__normal_iterator >>, cand_article*, bool ( )(cand_article , cand_article*)> (__first=, __last=, __pivot=@0x7f230412b350: 0x7f23fd297010, __ comp=0x7f24244d95e1 ) 在 /usr/包括/c++/4.8.3/bits/stl_algo.h:2266
  • 2 0x00007f24244f829c 在 std::__unguarded_pa​​rtition_pivot<__gnu_cxx::__normal_iterator >> 中, bool ( )(cand_article , cand_article*)> (__first=, __last=, __comp=0x7f24244d95e1 ) 位于 /usr/include/c++/4.8.3/bits/ stl_algo.h:2296
  • 3 0x00007f24244f1d88 in std::__introsort_loop<__gnu_cxx::__normal_iterator >>, long, bool ( )(cand_article , cand_article*)> (__first=, __last=, __depth_limit=18, __comp=0x7f24244d95e1 ) 位于 /usr/include/c++/ 4.8.3/位/stl_algo.h:2337
  • 4 0x00007f24244ed6e5 in std::sort<__gnu_cxx::__normal_iterator >>, bool ( )(cand_article , cand_article*)> ( __first=, __last=, __comp=0x7f24244d95e1 ) 位于 /usr/include/c++/4.8.3/bits/ stl_algo.h:5489

article_cmp被调用sort(article_result->begin(), article_result->end(), article_cmp);并且article_result是一个vector<cand_article*> *. cand_article是一个结构体。
这是 的定义article_cmp

bool article_cmp(cand_article* cand_article_1, cand_article* cand_article_2) {
    return cand_article_1 -> display_time >= cand_article_2 -> display_time;
}
Run Code Online (Sandbox Code Playgroud)

这是发生崩溃的一段代码:

 article_result->clear();
 for(vec_iter = _channel_data -> begin(); vec_iter != _channel_data -> end(); vec_iter++) {
     cand_article* cand = to_cand_group(*vec_iter);
     if(cand == NULL) continue;
     // refresh open loadmore
     if(m_request.req_type == 1) {
         if(cand -> display_time > m_request.start){
             article_result->push_back(cand);
         }
     }else if(m_request.req_type == 2){
         if(cand -> display_time < m_request.end){
             article_result->push_back(cand);
         }
     }else{
         article_result->push_back(cand);
     }
 }

 sort(article_result->begin(), article_result->end(), article_cmp);
Run Code Online (Sandbox Code Playgroud)

问题:

我不知道如何处理这种情况coredump,因为0x4015是内核空间地址?关于如何修复此类错误有什么建议吗?抱歉,我无法用最小的程序重现这种情况。而且这件事发生在a中single thread,所以你不需要考虑multi-thread情况。

Mar*_*ica 7

规则是“如果std::sort崩溃,则比较函数无效”。您的比较函数是:

bool article_cmp(cand_article* lhs, cand_article* rhs) {
    return lhs -> display_time >= rhs -> display_time;
}
Run Code Online (Sandbox Code Playgroud)

这不是严格的弱排序。特别是,如果显示时间相等,它会返回true,这意味着如果您交换参数,它仍然会返回true...,这是不允许的。你需要:

bool article_cmp(cand_article* lhs, cand_article* rhs) {
    return lhs -> display_time > rhs -> display_time;
}
Run Code Online (Sandbox Code Playgroud)

您的简化示例之所以有效(恭喜您至少尝试简化),是因为您简化了比较函数,因此它是有效的。如果 return 语句是return s1->it >= s2->it;,并且您使用了较小范围的值,它也可能会崩溃。

顺便说一句,示例结构的更自然的 C++ 声明如下所示:

struct st {                       // No need for that typedef in C++
    int it;
    char ch;
    std::string charr;            // ... or *possibly* std::array<char,100>.
    std::vector<std::string> vs;  // Strings and vectors best held by value
};
Run Code Online (Sandbox Code Playgroud)

另请注意,我实际上已经使用了std::前缀。