简体   繁体   中英

Handling an error condition in the compare function of std::qsort

I am trying to figure out a way for qsort to throw an exception or indicate an error condition if the compare function finds that the elements are, for some reason, invalid for sorting.

For example, in this compare function, I need to indicate an error condition that my sorting is invalid if the return value of some_function is 5 .

How should I modify my compare function?

int compare (const void * a, const void * b)
{
  int ret1 = some_func(a);
  int ret2 = some_func(b):
  return ( ret1 - ret2 );
}

I am dealing with a legacy code base so I'm not in the position to use std::sort and due to the nature of the implementation calling some_func before hand might also involve huge amount of changes so I'm looking to understand if a workaround is possible.

Throwing an exception is potentially expensive, so you probably want to return an error condition. However, doing either approach inside the compare function is needlessly expensive in this case, since you would be doing the check multiple times for every element. Instead, you could just check for the error condition before calling qsort which is much more efficient:

auto ok = std::none_of(/* range */, /* predicate */);

if (ok)
  std::qsort(/* ... */)
else
  // report error

C++ allows you to throw whatever you need, not only exceptions but also other types, you could do something like throw an int if it suits your purposes and catch where you call the function with a try-catch block.

For what you need I think you can use STL exception library:

Demostrative example :

#include <iostream>
#include <exception>

int count = 0;

int compare(const void *a, const void *b)
{  
    int ret1 = *(int*)a > *(int*)b;
    
    if (++count == 5) //throws exception when count reaches 5
        throw std::invalid_argument("Argument is not sortable");
    //you could throw count by simply using throw count

    return ret1;
}

int main()
{
    int x[]{2,1,3,5,6,1,7,2,5,3};
    try
    {
        //will sort until exception is thrown
        qsort(x, sizeof x / sizeof *x, sizeof(int), compare);
    }
    catch (const std::exception& e)
    {
        std::cout << e.what() << std::endl; //print exception in the console
        //handle the exception here
        //if you were to throw count you could cach it with
        //catch (int &e)
    }

    //note that the values were sorted until the exception was thrown
    for (int i = 0; i < sizeof x / sizeof *x; i++){
        std::cout << x[i] << " ";
    }
}

Output:

Argument is not sortable
1 2 3 5 6 1 7 2 5 3  
        ^
     sorting 
     stopped 
      here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM