C++: use own class in a multiset container

2019-07-04 19:21发布

问题:

at first I'm new here and English isn't my native language so apologize for any grammatical failures but I find this community really nice so I will try to ask my question as precise as I can.

I want to add my own class object into a stl container multiset and want to sort it with my own overloaded less operator defined in my class. I really tried out several solutions but nothing really worked so I hope someone can give me some useful hints to solve it.

Here is my general idea of my class definition:

class object {
public:
    int first;
    string second;

    object(int f, string s) {
         first = f;
         second = s;
    }

    bool operator<(const object &comp) {
        return first < comp.first;
        }
};

This was my first try and it didn't work so I also tried out to declare the overloaded operator as a friend method but it didn't work also.

Here is a short code extract from my main function:

includes ...
//code omitted
int main() {
    multiset<object*> mmset;

    mmset.insert(new object(10, "test"));
    mmset.insert(new object(11, "test"));

    return 0;
 }

After a while I started to debugging my code and try to figure out where the problem is and I come across the following thing that have made me a bit suspicious.

code extract from the stl:

// TEMPLATE STRUCT less
template<class _Ty>
struct less : public binary_function<_Ty, _Ty, bool>
    {   // functor for operator<
    bool operator()(const _Ty& _Left, const _Ty& _Right) const
    {   // apply operator< to operands
          return (_Left < _Right);
    }
    };

I have set a breakpoint on this line and observed what the program is doing here and I don't know why, but it only compares the addresses from the two objects and return so always false. It never calls my overloaded less operator although the operator exists and the _Left and _Right variables contain the address to my object.

I would really appreciate it if someone could help me.

Best Greetings

Tom

回答1:

You are not storing objects in your multiset. You are storing object*s. These are pointers to objects. This means the set will order the pointers that you're inserting into it.

It seems like you really just want a multiset<object>:

multiset<object> mmset;
mmset.emplace(10, "test");
mmset.emplace(11, "test");

Now it will use < to compare the objects themselves.

If you really want to store pointers, you'll need to provide a custom comparator to the multiset. In C++11, you can do this easily with a lambda:

auto f = [](int* a, int* b) { return *a < *b; };
std::multiset<int*, decltype(f)> mmset(f);

Pre-C++11, you can create a function object that implements operator() with the same body as this lambda function.



回答2:

Thank you for your help. That's seems to be a good solution to solve this problem.

I have searched a bit deeper in the new C++11 standard and found out that there is another possible solution to solve this with a little bit simpler implementation but the same result :) I will post it just as information for other seekers with the same problem.

You can pass any constructor a stl container a so-called comparison object which the container will use to arrange your content. The only thing you have to do is to define the overloaded operator() in your class and "misuse" them as a comparison operator.

class object {
    int first;
    string second;

    object() { };
    object(int f, string s) {
       first = f;
       second = s;
    }

    bool operator()(const object *comp1, const object *comp2) const {
       return comp1->first < comp2->first;
    }
}

The other thing what you have additionally to do now is to pass the object as the second argument in your definition of the container:

multiset(object*, object) mmset;

You can also use an extra class for this purpose just for comparison because otherwise you need a default constructor to use this class in this way.