From a C point of view, vector<float> does two things:
- Contain some floats
- Automatically free the memory it uses
Since 2 is an alien concept to C (nothing much happens automatically, certainly not freeing memory), there's no simple replacement. Basically you have three options. They are the same as the three options you have when you want functions to "return strings" in C, although here we need to tell the caller both a pointer and a length.
In my opinion, the third option is "the right answer", in the sense that it's the one you try first in your design, and if the design looks OK you stick with it. The first and second can be provided as convenience functions in cases where the calling code will really benefit from them, either wrapped around or alongside the third.
Return allocated memory
size_t c_wrapper(float **pResult) {
try {
std::vector<float> vec(cpp_function());
*pResult= (float*) std::malloc(vec.size() * sizeof(float));
if (!*pResult) { /* handle the error somehow */ }
std::copy(vec.begin(), vec.end(), *pResult);
return vec.size();
} catch (std::bad_alloc) { /* handle the error somehow */ }
}
Upside: Simple calling code.
Downside: The caller has to free the memory, even if the size is known in advance and the data would happily fit in a local array variable. Might be slow due to memory allocation.
Model: strdup (Posix)
Use shared static-duration resources
See jrok's answer:
size_t c_wrapper(float **pResult) {
try {
static std::vector<float> vec;
vec = cpp_function(); // or cpp_function().swap(vec) in C++03
*pResult = &vec[0];
return vec.size();
} catch (std::bad_alloc) { /* handle the error somehow */ }
}
Upside: Ridiculously simple calling code.
Downside: There is only one instance of save in the program, so the returned pointer only points to the correct data until the next time c_wrapper is called. In particular, this is very thread-unsafe. If the result is very large, then that memory is wasted from the time the caller no longer needs it until the time the function is next called.
Model: strtok, gethostbyname.
Write the data into a buffer provided by the caller
size_t c_wrapper(float *buf, size_t len) {
try {
std::vector<float> vec(cpp_function());
if (vec.size() <= len) {
std::copy(vec.begin(), vec.end(), buf);
}
return vec.size()
} catch (std::bad_alloc) { /* handle the error somehow */ }
}
Upside: Most flexible.
Downside: The caller has to pass in a big enough buffer (assuming cpp_function behaves consistently, caller can find out the size by calling the function with size 0 and a null pointer, get a big enough buffer from somewhere, then call the function again).
Model: strcpy, snprintf, getaddrinfo.