1

I have a project with a single .h file and multiple .cpp files. The header file contains a namespace UF (abbreviation for useful functions) that currently implements sorting.

This is done by having a comparator defined in UF.cpp thus:

    int compar_int_asc(const void *a, const void *b)
    {
        int aa = *((int *)a), bb = *((int *)b);
        if (base_arr_int[aa] < base_arr_int[bb])
            return -1;
        if (base_arr_int[aa] == base_arr_int[bb])
            return 0;
        if (base_arr_int[aa] > base_arr_int[bb])
            return 1;
    }

At present, the base array base_arr_int that needs to be accessed by qsort and the comparator function above is declared in main.cpp and externed in UF.cpp.

I access qsort within a different class, SEP as follows. Firstly, in SEP.cpp, I extern base_arr_int. Then, if ratios[100] is an integer array that is native and local to SEP, I do the following within SEP.cpp.

base_arr_int = ratios;
qsort(indices, 100, sizeof(int), UF::compar_int_asc);

Is this the best way of implementing qsort with multiple classes?

In particular, I would like to avoid using global variables defined in main.cpp as much as possible. Is there any alternative design?

Tryer
  • 3,580
  • 1
  • 26
  • 49
  • 3
    Would you like to consider `std::sort` instead of `qsort`? –  Sep 26 '17 at 01:52
  • @NickyC Yes, if it helps avoid global variables in main.cpp. Also, I don't sort the `ratios` array itself, but sort the `indices` so that `ratios[indices[0]]` is the smallest element, `ratios[indices[1]]`the next smallest and so on. Does `std::sort` help with that functionality? – Tryer Sep 26 '17 at 02:10

1 Answers1

1

The purpose of the global variable is to figuratively place the array inside the custom comparator. To eliminate the global variable, let's literally put ratio into the custom comparator. To do so, the custom comparator cannot be an ordinary function or function pointer. It needs to be a function object. And std::sort support that.

Let's do it step by step.


So, you have an array that store things.

int ratio[5] = {300, 400, 200, 500, 100};

But you don't want to sort it directly. You create an array of indice to which actually get sorted.

int indice[5] = {0, 1, 2, 3, 4};

The goal is to sort indice. So let's write:

std::sort(indice, indice + 5);

But it is not what you want yet. You also need to pass a custom comparator index_comp because the default less-than comparator is not what you need.

std::sort(indice, indice + 5, index_comp);

The rest of the work is how to write index_comp. It is actually quite simple: lambda expression

auto index_comp = [&ratio](int index_left, int index_right) { return ratio[index_left] < ratio[index_right]; };

This lambda expression captures the array ratio by reference ([&ratio]). It has a parameter list taking two indice. The body compares the two actual objects in ratio.

If you prefer the old school way, the lambda expression is just a syntax sugar of the following:

class Compiler_Generated_Name
{
private:
    int (&ratio)[5];

public:
    Compiler_Generated_Name(int (&ratio_)[5]) : ratio(ratio_) {}

    bool operator()(int index_left, int index_right)
    {
        return ratio[index_left] < ratio[index_right];
    }
};

Compiler_Generated_Name index_comp(ratio);

The whole code:

#include <iostream>
#include <algorithm>

int main()
{
    int ratio[5] = {300, 400, 200, 500, 100};
    int indice[5] = {0, 1, 2, 3, 4};

    auto index_comp = [&ratio](int index_left, int index_right) { return ratio[index_left] < ratio[index_right]; };

    std::sort(indice, indice + 5, index_comp);

    for (int i = 0; i < 5; ++i)
        std::cout << ratio[indice[i]] << ' ';
}
  • I am having some trouble implementing this. In my `SEP` class, I have `ratio` declared as `int *ratio`. I then dynamically new this in order to populate the values. Then, I have `std::sort(indexofarray, indexofarray + 5, [&ratio](int index_left, int index_right) { return ratio[index_left] < ratio[index_right]; });` within a member function of `SEP` but this gives me the following error: `member "SEP::ratio" is not a variable` – Tryer Sep 26 '17 at 05:46
  • 1
    In the case of member variable, you can capture the `this` pointer, as in `[this](int index_left, int index_right) { ... };` See https://stackoverflow.com/questions/7895879 –  Sep 26 '17 at 06:45