Reputation:
I have a C++ function which returns a std::vector<float>
.
I am interfacing with some C code.
How do I change this C++ function so that it returns some pointer to a float array, and how do I save this returned array so that I can use it in my C code?
Upvotes: 0
Views: 736
Reputation: 279325
From a C point of view, vector<float>
does two things:
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.
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)
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
.
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
.
Upvotes: 1
Reputation: 55425
You could save the returned temporary vector in a vector object with static storage duration.
std::vector<float> foo()
{
return std::vector<float>();
}
float* call_foo_and_get_pointer()
{
static std::vector<float> save; // this line is executed only at the first
// call to enclosing function
save = foo();
return save.data(); // or &data[0]
}
The pointer returned from call_foo_and_get_pointer
is guaranteed to stay valid until the next call to it.
Upvotes: 0
Reputation: 437574
You can get a pointer to a "raw" array with std::vector::data
or &my_vector[0]
if C++11 is not available. However, if a vector operation forces the vector to be resized then the raw storage will move around in memory and this pointer will no longer be safe to use. If there is any possibility of this happening, you will need to allocate separate storage (e.g. by creating a copy of the vector
) and provide a pointer to that instead.
Update: Woodrow's comment made me notice that you are actually after returning a pointer from a function. You can only return pointers to heap-allocated memory, so you cannot use a local vector
(or any other type of stack-allocated memory) to do this.
Upvotes: 5
Reputation: 30
#include <vector>
#include <iostream>
int main()
{
std::vector<float> vec;
vec.push_back(1.23);
vec.push_back(3.123);
int len = vec.size();
float *arr = new float[len];
std::copy(vec.begin(),vec.end(),arr);
for(int i = 0; i < sizeof(arr)/sizeof(arr[0]); ++i){
std::cout << arr[i] << "\n";
}
delete [] arr;
return 0;
}
Upvotes: 0