Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting "Debug Assertion Failed!" for set comparator

I know similar issue has been answered at this link Help me fix this C++ std::set comparator but unfortunately I am facing exactly same issue and I am unable to understand the reason behind it thus need some help to resolve it.

I am using VS2010 and my release binary is running fine without any issue but the debug binary reports:

enter image description here

My comparator looks like this:

struct PathComp {
    bool operator() (const wchar_t* path1, const wchar_t* path2) const
    {
        int c = wcscmp(path1, path2);
        if (c < 0 || c > 0) {
            return true;
        }
        return false;
    }
};

My set is declared like this:

set<wchar_t*,PathComp> pathSet;

Could somebody suggest me why my debug binary is failing at this assertion? Is it because I am using wcscmp() function to compare the wide character string getting stored in my set?

Thanks in advance!!!

like image 759
sactiw Avatar asked Apr 28 '11 18:04

sactiw


3 Answers

std::set requires a valid comperator that behaves like operator< or std::less.

The std::set code detected that your operator< is not valid, and as a help to you triggered the assert you showed.

And indeed: your comperator looks like an operator!=, not like an operator<

One of the rules an operator< should follow, is that a<b and b<a cannot be both true. In your implementation, it is.

Correct your code to:

bool operator() (const wchar_t* path1, const wchar_t* path2) const
{  
  int c = wcscmp(path1, path2);
  return (c < 0);
}

and you should be fine.

like image 127
Sjoerd Avatar answered Sep 24 '22 01:09

Sjoerd


The problem is that your comparator does not induce a strict-weak ordering. It should only really return true for paths that are "less" - not for all that are different. Change it to:

struct PathComp {
    bool operator() (const wchar_t* path1, const wchar_t* path2) const
    {
        int c = wcscmp(path1, path2);
        if (c < 0) {  // <- this is different
            return true;
        }
        return false;
    }
};

Alternatively, using only c > 0 will also work - but the set will have a reverse order.

The algorithm needs to know the difference between smaller and greater to work, just unequal does not give enough information. Without smaller-than/greater-than information, the set cannot possibly maintain an order - but that is what a set is all about.

like image 26
ltjax Avatar answered Sep 24 '22 01:09

ltjax


After spending some more time on it we finally decided to take another approach which worked for me.

So we converted wchar_t* to string using this method:

// Converts LPWSTR to string
bool convertLPWSTRToString(string& str, const LPWSTR wStr)
{
    bool b = false;
    char* p = 0;
    int bSize;    
    // get the required buffer size in bytes
    bSize = WideCharToMultiByte(CP_UTF8,
        0,
        wStr,-1,
        0,0,
        NULL,NULL);     
    if (bSize > 0) {
        p = new char[bSize];
        int rc = WideCharToMultiByte(CP_UTF8,
            0,
            wStr,-1,
            p,bSize,
            NULL,NULL);
        if (rc != 0) {
            p[bSize-1] = '\0';
            str = p;
            b = true;
        }
    }
    delete [] p;
    return b;
}

And then stored that string in the in the set, by doing this I didn't had to worry about comparing the elements getting stored to make sure that all entries are unique.

// set that will hold unique path
set<string> strSet;

So all I had to do was this:

string str;
convertLPWSTRToString(str, FileName);
// store path in the set
strSet.insert(str);

Though I still don't know what was causing "Debug Assertion Failed" issue when I was using a set comparator (PathComp) for set<wchar_t*,PathComp> pathSet;

like image 40
sactiw Avatar answered Sep 23 '22 01:09

sactiw