0

STL set can have customized comparator. It can be implemented in several ways, such as define an operator(), use decltype on lambda, etc. I was trying to use a static method of a class and encountered a weird crash. The crash can be demonstrated by the following code

#include <string>
#include <set>

struct Foo {
        static bool Compare(std::string const& s1, std::string const& s2)
        {
                return s1 < s2;
        }
};

std::set<std::string, decltype(&Foo::Compare)> S;

int main()
{
        S.insert("hello");
        S.insert("world");

        return 0;
}

The crash happened on the second insert. Thank you.

2 Answers2

1

You have to pass pointer to compare function to set constructor, otherwise it is null and it is why the code fails.

std::set<std::string, decltype(&Foo::Compare)> S{&Foo::Compare};

By decltype(&Foo::Compare) you only specify the type of comparator, it has to be provided because its default value is null.

rafix07
  • 20,001
  • 3
  • 20
  • 33
  • I see. Thank you so much! Using the constructor of set to specify the instance of the comparator resolves the problem. The default constructed object of the function pointer is null. – Hongzheng Wang Jan 16 '22 at 07:34
1

Change your code to below will solve the problem.

struct Foo {
        bool operator()(std::string const& s1, std::string const& s2)
        {
                return s1 < s2;
        }
};

std::set<std::string, Foo> S;

The original program crushes because the constructor of set will try to call the constructor of decltype(&Foo::Compare) which is actually not constructible.

  • 1
    "which is actually not constructible": It is default-constructible. `decltype(&Foo::Compare)` is a function pointer type and will default-construct to a null pointer value. Calling the null pointer then is UB and crashes. – user17732522 Jan 15 '22 at 08:47
  • Thank you so much for pointing out this @user17732522. – Hongzheng Wang Jan 16 '22 at 07:36