3

I have a C++ class but I'm also using some low level C and need to use the bsearch function. The last argument of bsearch is a comparison function, and I want to implement said function in a way that will allow it to access const private variables of the class.

The problem is that if I make the comparison function a member function it will not work, because it won't be a convertible to a regular function pointer. If I make a non member function I can pass that to bsearch, but would not able to access private variables of the class.

What to do?

example: enter image description here

3 means there are 3 elements.16,32,56 are offset bytes.I need bsearch to search for actors.I'm searching in the offset array.I need a comparison function which would compare actors but i laso need const void * actorFile pointer to compute the locations in the comparison function.actorFIle is class private variable.

sparrow2
  • 147
  • 1
  • 11
  • @StoryTeller Thanks for quick reply.Can't it be done using pure bsearch?Also I had a quick glimpse of lower_bound and it also needs a cmp function,how is it any different in this case from bsearch? – sparrow2 Oct 10 '17 at 07:52
  • `std::lower_bound` can take any kind of functor (a function, or an object that has the operator() defined, including lambdas). And with an object, you can hold whatever variables you need to do the comparison. – kmdreko Oct 10 '17 at 07:55
  • your compare function can be a free function if you provide a getter for the private member. Private members arent there to be accessed from outside the class, if you need to access it make it public or provide a way to access it – 463035818_is_not_an_ai Oct 10 '17 at 07:55
  • 1
    @tobi303 - The free function still needs an instance of the class. With `bsearch` one would have to resort to globals. That's a smell. – StoryTeller - Unslander Monica Oct 10 '17 at 07:58
  • @StoryTeller I dont understand, "The free function still needs an instance of the class" ? the free function would be `int compare(const void*,const void*)` and the instances get passed as parameters. btw by no means I am trying to defend using bsearch – 463035818_is_not_an_ai Oct 10 '17 at 08:01
  • @tobi303 - The OP's issue, as I see it, is that their class *calls* `bsearch` on some low level C stuff. Not that `bsearch` is used to sort class instances (which will be terrible). – StoryTeller - Unslander Monica Oct 10 '17 at 08:03
  • @StoryTeller ah ok, seems like I misunderstood the question – 463035818_is_not_an_ai Oct 10 '17 at 08:04
  • @tobi303 - Actually, your point of view makes me think I may have misunderstood it. I fixed the phrasing of the question, but it may still be unclear. – StoryTeller - Unslander Monica Oct 10 '17 at 08:05
  • 1
    @StoryTeller without code it is always hard to tell... – 463035818_is_not_an_ai Oct 10 '17 at 08:07
  • 2
    please provide a [mcve]. The question is not 100% clear. What do you want to search? Why do you think you need to access a private member? – 463035818_is_not_an_ai Oct 10 '17 at 08:08

2 Answers2

7

The solution is to forgo the C library function, and use C++ as it's meant to be used. The C++ standard library also has a utility search function, it's called std::lower_bound. And it accepts general function-like objects, not just regular function pointers.

This allows you to call it with a lambda expression that captures your class:

std::lower_bound(start, finish, value, [this] (auto const& lhs, auto const& rhs) {
                 /* Compare and utilize anything this can point to*/ });
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • using lower_bound would be better,but I'm really tied to bsearch. – sparrow2 Oct 10 '17 at 08:28
  • @sparrow2 - I really don't see how. `bsearch` works *only* with plain arrays, `lower_bound` works *also* with plain C arrays. – StoryTeller - Unslander Monica Oct 10 '17 at 08:30
  • @sparrow2 You can't have your cake and eat it. `bsearch` is a C function that knows nothing about classes and member functions. – David Haim Oct 10 '17 at 08:30
  • @StoryTeller I run bsearch on the offsets,in the example 16,32,56 but in comparision function I compare real info,that's why I need actorFile to compute where real info is. – sparrow2 Oct 10 '17 at 08:35
  • @sparrow2 - Your post doesn't have an example, it has a diagram and some hand waving. A proper example (a [mcve]). Would have a sample C and C++ code that shows what you try to do. We aren't going to guess how to help you. You have to tell us. – StoryTeller - Unslander Monica Oct 10 '17 at 08:39
1

If you are really tied to bsearch just use your member function inside the non member function. Hence you don't need to access private members.

/* Create global variable to use in compare proc*/
actors_data_base* cmp_data_base = NULL;

/* Write compare routine like */
int cmp_proc(const void * a, const void * b)
{
    size_t a_offset = static_cast<size_t>(a);
    size_t b_offset = static_cast<size_t>(b);
    return cmp_data_base->compare_actors(a_offset, b_offset);
}


/* Set global pointer and use bsearch */
actors_data_base = &my_data_base;
bsearch(&my_value, array, size, sizeof(size_t), cmp_proc);

Definitely, this is ugly, due to use of global variable. But this is the only way to pass a context to compare proc. You may think of using thread local storage to avoid threading issues (cmp_proc must not be used concurrently due to global var)

Hence, you would much and much better to use std::lower_bound.

ivaigult
  • 6,198
  • 5
  • 38
  • 66
  • The compiler will not let me use member function inside non member function in the class file,If i don't have an instance and call the member method of that instance – sparrow2 Oct 10 '17 at 08:09
  • Let me clarify. I will add an example. – ivaigult Oct 10 '17 at 08:10