Reputation: 15366
I'm working on a legacy code base that has this pattern:
struct sometype_t { /* ... */ };
int some_method(void *arg1) { // void pointer
((sometype_t*)arg1)->prop1; // cast
}
Is there any (common) scenario where it would be unsafe to use sometype_t *
instead of void *
?
int some_method(sometype_t *arg1) {
arg1->prop1;
}
The pointer isn't passed across ABIs or into 3rd-party libraries; it stays entirely within C++ code that we own.
Upvotes: 1
Views: 790
Reputation: 320541
The obvious common scenario that immediately comes to mind is callbacks for some functions from C standard library.
For example, the proper way to write the comparison callback for std::qsort
is to declare the function with two const void *
arguments and then cast them to proper specific pointer types inside the callback.
Replacing these const void *
parameters with specifically-typed pointers will simply prevent the code from compiling.
Upvotes: 0
Reputation: 17694
It's usually not a good choice, but the only situation I'm aware of where this really make sense is if you want to have stateful callbacks passed into a function, without using templates:
void takes_callback(void(*f)(void*), void * data);
Basically the gist is that since you aren't using templates, you have to fix the function signature you accept (of course, it can and often does take other arguments and return something as well). If you just call the function with your own parameters though, the function can only hold state between calls via global variables. So instead the contract for takes_callback
promises to call f
with data
as a parameter.
So, if you wanted to use some_method
as a callback in such an API, you would have to have it take void*
, and do the cast internally. Obviously, you are throwing away type safety here, and if you happen to call takes_callback
with &somemethod
and a pointer to anything that's not a sometype_t
you have UB.
Having a C ABI is one reason to avoid templates, but it's not the only one. Maybe they were worried about code bloat, or wanted to keep the implementation in a .so so that versions could be upgraded without recompiling, etc.
Upvotes: 2