Reputation: 115
I want to pass a c++ reference to a c style API that only allows pointer arguments for passing custom data.
In my example i simply cast the address of the c++ reference into a pointer to void (which happens in a function called "function"). This pointer is being passed to a c function (which is called "execute") which also takes a callback function as a parameter. Inside the callback functions implementation (named "callback") i cast the pointer to void back to a pointer to std::vector.
This compiles without warning(s) and error(s) in MS Visual Studio 2017 and runs as desried (the vector "v" contains the numbers from 1 to 5 and they are also printed). However i'm afraid wether this is valid according to the C++ standard.
Of course there is the possiblity of using a global std::vector instance. But under some circumstances, as in my case, this might be a bad solution. Because in my case i need an instance of std::vector per call to "function", therefore it's not suitable to have one global instance replacing the parameter. Also global instances might be inappropriate in multithreaded environments, where i want to keep instances of std::vector on the calling stack per thread. Wrapping the std::vector instance by a class and passing a pointer to a std::vector member is also not really what i'm looking for. I'm rather curious about the technical view on the specific implementation i have used.
In a nutshell, would we consider this example a bad practice? Is it valid to take the address of a reference to Type into a pointer to void and cast back from a pointer to void into a pointer to Type while neglecting that the pointee originally was a reference to Type. Are there alternatives instead of the ones i have described above?
Please find the minimal working example below:
#include <vector>
#include <iostream>
//
// The API of a 3rd party library (Typical C-Style Interface)
//
void execute(void (*callback)(void *, int[], int), void * context)
{
int data [5] = {1,2,3,4,5};
(*callback)(context, data, 5);
}
//
// My callback function fitting the signature for the 3rd party API
//
void callback(void * context, int data [], int size)
{
std::vector<int> * v = (std::vector<int> *)context;
for (int i = 0; i < size; i++) {
v->push_back(data[i]);
}
}
//
// Pass a reference to an std::vector as void * to the 3rd party API
//
void function(std::vector<int> & v)
{
execute(callback, (void *)&v);
}
//
// Pass a std::vector as reference to a function
//
// Evaluate the result at the end
//
int main()
{
std::vector<int> v;
function(v);
for (auto & e : v) {
std::cout << e << std::endl;
}
return 0;
}
Upvotes: 0
Views: 2801
Reputation: 409176
You can't actually do anything with a reference variable except initialize it on definition. Every use of the reference variable after initialization is a direct access to the original variable, what it references.
In your case, when you do &v
in the function function
, you don't get the address of the local reference variable v
, but the address of the variable v
from the main
function.
In short, this is fine.
Upvotes: 1