Sorting a vector of custom objects

后端 未结 13 2975
既然无缘
既然无缘 2020-11-21 05:14

How does one go about sorting a vector containing custom (i.e. user defined) objects.
Probably, standard STL algorithm sort along with a predicate (a fu

13条回答
  •  囚心锁ツ
    2020-11-21 05:40

    I was curious if there is any measurable impact on performance between the various ways one can call std::sort, so I've created this simple test:

    $ cat sort.cpp
    #include
    #include
    #include
    #include
    
    #define COMPILER_BARRIER() asm volatile("" ::: "memory");
    
    typedef unsigned long int ulint;
    
    using namespace std;
    
    struct S {
      int x;
      int y;
    };
    
    #define BODY { return s1.x*s2.y < s2.x*s1.y; }
    
    bool operator<( const S& s1, const S& s2 ) BODY
    bool Sgreater_func( const S& s1, const S& s2 ) BODY
    
    struct Sgreater {
      bool operator()( const S& s1, const S& s2 ) const BODY
    };
    
    void sort_by_operator(vector & v){
      sort(v.begin(), v.end());
    }
    
    void sort_by_lambda(vector & v){
      sort(v.begin(), v.end(), []( const S& s1, const S& s2 ) BODY );
    }
    
    void sort_by_functor(vector &v){
      sort(v.begin(), v.end(), Sgreater());
    }
    
    void sort_by_function(vector &v){
      sort(v.begin(), v.end(), &Sgreater_func);
    }
    
    const int N = 10000000;
    vector random_vector;
    
    ulint run(void foo(vector &v)){
      vector tmp(random_vector);
      foo(tmp);
      ulint checksum = 0;
      for(int i=0;i & v)){
    
    ulint check_sum = 0;
    
      // warm up
      const int WARMUP_ROUNDS = 3;
      const int TEST_ROUNDS = 10;
    
      for(int t=WARMUP_ROUNDS;t--;){
        COMPILER_BARRIER();
        check_sum += run(foo);
        COMPILER_BARRIER();
      }
    
      for(int t=TEST_ROUNDS;t--;){
        COMPILER_BARRIER();
        auto start = std::chrono::high_resolution_clock::now();
        COMPILER_BARRIER();
        check_sum += run(foo);
        COMPILER_BARRIER();
        auto end = std::chrono::high_resolution_clock::now();
        COMPILER_BARRIER();
        auto duration_ns = std::chrono::duration_cast>(end - start).count();
    
        cout << "Took " << duration_ns << "s to complete round" << endl;
      }
    
      cout << "Checksum: " << check_sum << endl;
    }
    
    #define M(x) \
      cout << "Measure " #x " on " << N << " items:" << endl;\
      measure(x);
    
    int main(){
      random_vector.reserve(N);
    
      for(int i=0;i

    What it does is it creates a random vector, and then measures how much time is required to copy it and sort the copy of it (and compute some checksum to avoid too vigorous dead code elimination).

    I was compiling with g++ (GCC) 7.2.1 20170829 (Red Hat 7.2.1-1)

    $ g++ -O2 -o sort sort.cpp && ./sort
    

    Here are results:

    Measure sort_by_operator on 10000000 items:
    Took 0.994285s to complete round
    Took 0.990162s to complete round
    Took 0.992103s to complete round
    Took 0.989638s to complete round
    Took 0.98105s to complete round
    Took 0.991913s to complete round
    Took 0.992176s to complete round
    Took 0.981706s to complete round
    Took 0.99021s to complete round
    Took 0.988841s to complete round
    Checksum: 18446656212269526361
    Measure sort_by_lambda on 10000000 items:
    Took 0.974274s to complete round
    Took 0.97298s to complete round
    Took 0.964506s to complete round
    Took 0.96899s to complete round
    Took 0.965773s to complete round
    Took 0.96457s to complete round
    Took 0.974286s to complete round
    Took 0.975524s to complete round
    Took 0.966238s to complete round
    Took 0.964676s to complete round
    Checksum: 18446656212269526361
    Measure sort_by_functor on 10000000 items:
    Took 0.964359s to complete round
    Took 0.979619s to complete round
    Took 0.974027s to complete round
    Took 0.964671s to complete round
    Took 0.964764s to complete round
    Took 0.966491s to complete round
    Took 0.964706s to complete round
    Took 0.965115s to complete round
    Took 0.964352s to complete round
    Took 0.968954s to complete round
    Checksum: 18446656212269526361
    Measure sort_by_function on 10000000 items:
    Took 1.29942s to complete round
    Took 1.3029s to complete round
    Took 1.29931s to complete round
    Took 1.29946s to complete round
    Took 1.29837s to complete round
    Took 1.30132s to complete round
    Took 1.3023s to complete round
    Took 1.30997s to complete round
    Took 1.30819s to complete round
    Took 1.3003s to complete round
    Checksum: 18446656212269526361
    

    Looks like all the options except for passing function pointer are very similar, and passing a function pointer causes +30% penalty.

    It also looks like the operator< version is ~1% slower (I repeated the test multiple times and the effect persists), which is a bit strange as it suggests that the generated code is different (I lack skill to analyze --save-temps output).

提交回复
热议问题