0

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?

4 Answers 4

5

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Also be sure that the array isn't allocated on the stack of the function that's returning it, or the pointer will go invalid pretty quick.
@WoodrowDouglass: It took your comment to make me realize they said "return some pointer from a function" => 99% probability of making this mistake if naively adapting the code. Thanks!
Technically you can return a pointer to an array allocated on stack, if you pass it on input, or if you allocate it statically. I read that a few times eskimo.com/~scs/cclass/int/sx5.html for an explanation of all the ways to return array.
@DimitarSlavchev - If it's allocated statically, it's not on the stack. I agree this can work if it's passed on input, but you have to be careful about the function hierarchy.
1

From a C point of view, vector<float> does two things:

  1. Contain some floats
  2. 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.

Comments

0

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.

5 Comments

return &data[0]; then, didn't you see the comment?
still the same..I am lost here..where does data come from?
it should be return &save[0]; I think
Ah yes, sorry, that was a typo.
Th pointer points to the vector's internal storage. Since it's guranteed to be contiguous by the standard, you can treat it as an array.
0
#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;
}

2 Comments

So... how does this answer the question?
I think this is a most of a solution since the original question asks "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?" So the answer with respect to this code would be : add the main() lines 4 through 9 to the end of your C++ function and also "return arr". Capture that and pass it to the C routine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.