Search code examples
c++11pointerssetuser-defined-typescustom-compare

Custom compare class not working as I expect for pointers to a user defined class in a std::set container


I can't figure out why in this code example the std::set container is not ordering the Entities as I expect on the basis of the compare class I defined. Anyone can help me please? Thanks

 #include <iostream>
 #include <set>

 class Entity {
 public:
 int num;
 Entity(int num):num(num){}
     bool operator< (const Entity& _entity) const { return (this->num < _entity.num); }
 };

 struct my_cmp {
     bool operator() (const Entity* lhs, const Entity* rhs) const { return (lhs < rhs); }
 };

 class EntityManager {
     private:
        std::set<Entity*, my_cmp> entities;
   public:
        void AddEntity(int num) { entities.insert(new Entity(num)); }
        void ListAllEntities() const {
              unsigned int i = 0; 
              for (auto& entity: entities) {
                  std::cout << "Entity[" << i << "]: num:" << entity->num << std::endl;
                  i++;
              }
         }
};

int main(void) {
    EntityManager manager;
    manager.AddEntity(2);
    manager.AddEntity(1);
    manager.AddEntity(4);
    manager.AddEntity(3);
    manager.ListAllEntities();
    return 0;
}

Output:

Entity[0]: num:2

Entity[1]: num:1

Entity[2]: num:4

Entity[3]: num:3

I would expect the following output instead:

Entity[1]: num:1

Entity[0]: num:2

Entity[3]: num:3

Entity[2]: num:4


Solution

  • You need to dereference your pointers *lhs < *rhs. You're just comparing the value of the pointers currently, so your order is dependent on their location in memory.

    #include <iostream>
     #include <set>
    
     class Entity {
     public:
     int num;
     Entity(int num):num(num){}
         bool operator< (const Entity& _entity) const { return (this->num < _entity.num); }
     };
    
     struct my_cmp {
         bool operator() (const Entity* lhs, const Entity* rhs) const { return (*lhs < *rhs); }
     };
    
     class EntityManager {
         private:
            std::set<Entity*, my_cmp> entities;
       public:
            void AddEntity(int num) { entities.insert(new Entity(num)); }
            void ListAllEntities() const {
                  unsigned int i = 0; 
                  for (auto& entity: entities) {
                      std::cout << "Entity[" << i << "]: num:" << entity->num << std::endl;
                      i++;
                  }
             }
    };
    
    int main(void) {
        EntityManager manager;
        manager.AddEntity(2);
        manager.AddEntity(1);
        manager.AddEntity(4);
        manager.AddEntity(3);
        manager.ListAllEntities();
        return 0;
    }
    

    Demo