Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort a std::list<myclass*> with myclass::operator<(myclass &other)

Tags:

c++

std

I have a std::list<myclass*> and in my class I have myclass::operator<(myclass &other) defined.

I use the std::list.sort() function, but it does not change anything in that list. Maybe it just sorts the pointers?

How can I sort the actual items in that list?

like image 683
Martin Ueding Avatar asked Jun 19 '11 18:06

Martin Ueding


3 Answers

You are sorting the pointer values, not the myclass values. You have to write your own predicate to compare pointers by dereference:

template <typename T> bool PComp(const T * const & a, const T * const & b)
{
   return *a < *b;
}

std::vector<Foo*> myvec;
std::list<Foo*> mylist;
std::sort(myvec.begin(), myvec.end(), PComp<Foo>);
mylist.sort(PComp<Foo>);

By the way, I think you cannot sort std::list with std::sort from <algorithm> because it is not random access. Use the member function sort instead as MerickOWA says. (But that's generally less efficient than sorting a random-access container.) Alternatively, you can immediately store your objects in a sorted container like std::set<Foo*, PPred>, where PPred is the functor version of the predicate:

struct PPred {
  template <typename T> inline bool operator()(const T * a, const T * b) const
  { return *a < *b; }
};
like image 143
Kerrek SB Avatar answered Nov 15 '22 14:11

Kerrek SB


Several answers propose using a predicate that explicitly takes two pointers; this will work for your current case where you have a container of raw pointers, but it won't work for any other dereferenceable type, like smart pointers or iterators.

Why not go the more general route and match any type?

struct indirect_compare
{
    template <typename T>
    bool operator()(const T& lhs, const T& rhs) const 
    {
        return *lhs < *rhs;
    }
}

While a const reference is unnecessary for a T*, it is necessary for smart pointer types that are relatively expensive to copy (e.g. std::shared_ptr) or impossible to copy (e.g. std::unique_ptr).

Alternatively, you might consider using something like Boost's indirect_iterator, which moves the indirection into the iterator and can make for much cleaner code.

like image 44
James McNellis Avatar answered Nov 15 '22 13:11

James McNellis


It'll sort the pointer as std::sort( Container ) use the operator< defined T. Here T is myclass*, then it is sorted using comparison over pointer.

You can pass a custom comparator functor to std::sort so make one take takes two myclass* and return the proper comparison :

template<class T>
struct ptr_comparison
{
   bool operator()(T* a, T* b) { return *a < *b; } 
};

list<myclass*> mylist;

// later

mylist.sort(ptr_comparison<myclass>());
like image 41
Joel Falcou Avatar answered Nov 15 '22 15:11

Joel Falcou