2

So an Instanced API is one that behaves like an object. So for example:

foo* GetInstancedAPI();
void MemFuncSetter(foo* fooThis, const int arg);
int MemFuncGetter(const foo* fooThis) const;

This is as opposed to a non-instanced API which would depend upon look-ups:

int GetInstancedAPI();
void MemFuncSetter(const int index, const int arg);
int MemFuncGetter(const int index) const;

A little background about the situation, this is a C API, that's being used to wrap a C++ implementation. So internally to the implementation I am working with objects. So I've tried to think through the ramifications of each, the biggest issues I can think of are:

  • How would I handle callbacks?
  • Is there a way minimize the lookup cost?

Edit:
There have been a lot of requests for clarifications: foo* is really a void pointer in the C interface which will be reinterpret_cast into a pointer to the actual C++ object, thus it must be passed in.
The functions that take an int are with the intention of indexing into an vector of objects in the wrapped C++.

3 Answers3

7

Is there a way minimize the lookup cost?

Yes- don't use a lookup. Instanced APIs are the way to go - non-instanced ones suffer from terrible problems like not having separate instances be concurrently accessed from multiple threads, invisible dependencies and other such issues.

DeadMG
  • 36,914
2

Callbacks are handled the same way every callback should be handled in C, a function pointer and a void* userdate/context pointer. The function pointer takes the parameters it needs and the context pointer which it can then use to access the state it needs.

Lookup cost is just one extra memory lookup compared to using globals for your state and no different than using C++ member functions which do the same thing (this gets passed as a hidden parameter).

ratchet freak
  • 25,986
2

I see no practical difference between the example you've given.

In the first case you've returned a pointer to an object. In the second, you've returned an index of that object in an array.

C defines array access and pointer access as being essentially equivalent. array[index] = *(array + index). So in one case, you've done an addition (and possibly scaling) before returning the pointer, while in the other you do them while accessing the item.

In theory, that can/should favor the pointer (every so slightly), since it does the addition/scaling only once instead of multiple times. In reality, it's not necessarily that simple. On a modern system, a pointer will often be 64 bits. Since there's essentially no chance of your really wanting to be able to return 1.8x1019 separate items, you can typically use a much smaller number for your index--a single char is often more than sufficient.

In this case, loading and passing a char can be enough faster to more than compensate for the adding and scaling so using the index actually turns out (slightly) faster.

As for access from multiple threads and such go...it depends. It's certainly true that the index carries an implicit dependency on the array into which it indexes. If you're going to pass the index across thread boundaries, you have to ensure that the array is accessible from all the relevant threads (but with most systems, that's the default and you'd have to specify it explicitly to get something thread-local). At least in the normal code, that array is read-only, so you don't have to lock it to get access.

You might or might not need to do some locking in the object itself, but it's basically irrelevant, because using a pointer vs. index to find the object isn't going to affect how (or if) you need to do locking inside the object.

Jerry Coffin
  • 44,795