Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting vector of smart pointers: mysterious crash

I am trying to sort a vector of smart pointers to a class. I use a struct as the third parameter to std::sort with operator():

struct PhraseSmartPtrParseCreationComparer
{
    bool operator()(const std::shared_ptr<Phrase>& a, const std::shared_ptr<Phrase>& b)
    {
        if (a.get() == nullptr)
            return b.get() != nullptr;
        if (b.get() == nullptr)
            return a.get() != nullptr;
        return *a < *b;
    }
};

Once in a while, I get a segmentation fault where one of the pointers inside the comparing method points to an invalid structure; always one. The interesting bit is, just before the sort, all the objects are intact; I also tried modifying the function to remove the reference bit: const std::shared_ptr<Phrase> a, and it crashed elsewhere.

The call is nothing fancy:

std::sort(_detectedPhrases.begin(), _detectedPhrases.end(), PhraseSmartPtrParseCreationComparer()); 

Is there something I'm missing or I should be looking elsewhere?

like image 335
Vadim Berman Avatar asked Oct 17 '22 15:10

Vadim Berman


1 Answers

I can't believe how fast it was resolved. Here is the explanation - thank you for your guidance and cues, @BoBTFish and @Jabberwocky.

Indeed, the reason was that the sorter was having it both ways. The result was not symmetric. That is, the same two items, when swapped, could sometimes produce the same answer. Unfortunately, because of the business logic, it was actually valid. It's basically a tree, and one of the comparison components was whether one item is allowed to be a parent of the other - and a situation when both could theoretically be parents of the other is valid. So I did not change that. What I did (and hopefully it's not bad taste) was to add this workaround (never mind the nullptr checks, they are not relevant):

struct PhraseSmartPtrParseCreationComparer
{
    bool operator()(const std::shared_ptr<Phrase>& a, const std::shared_ptr<Phrase>& b)
    {
       return *a < *b && !(*b < *a);    
    }
};
like image 143
Vadim Berman Avatar answered Oct 20 '22 21:10

Vadim Berman