我有一个 C++ 函数,它返回一个std::vector<float>
.
我正在与一些 C 代码交互。
如何更改此 C++ 函数以使其返回一些指向浮点数组的指针,以及如何保存此返回的数组以便在我的 C 代码中使用它?
如果 C++11 不可用std::vector::data
,您可以获得指向“原始”数组的指针。&my_vector[0]
但是,如果向量操作强制调整向量的大小,那么原始存储将在内存中移动,并且该指针将不再安全使用。如果有可能发生这种情况,您将需要分配单独的存储空间(例如,通过创建 的副本vector
)并提供指向该存储空间的指针。
更新:伍德罗的评论让我注意到您实际上是在从函数返回指针之后。您只能返回指向堆分配内存的指针,因此您不能使用本地vector
(或任何其他类型的堆栈分配内存)来执行此操作。
从 C 的角度来看,vector<float>
做了两件事:
由于 2 对 C 来说是一个陌生的概念(不会自动发生任何事情,当然不会释放内存),因此没有简单的替代方法。基本上你有三个选择。它们与您希望函数在 C 中“返回字符串”时的三个选项相同,尽管在这里我们需要告诉调用者一个指针和一个长度。
在我看来,第三个选项是“正确答案”,从某种意义上说,它是你在设计中首先尝试的选项,如果设计看起来不错,你就坚持下去。第一个和第二个可以作为便利函数提供,以防调用代码真正受益于它们,或者包裹在第三个周围或旁边。
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 */ }
}
优点:简单的调用代码。
缺点:调用者必须free
占用内存,即使预先知道大小并且数据很乐意放入本地数组变量中。由于内存分配,可能会很慢。
型号:strdup
(Posix)
请参阅 jrok 的回答:
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 */ }
}
优点:简单得可笑的调用代码。
缺点:程序中只有一个实例save
,所以返回的指针只指向正确的数据,直到下一次c_wrapper
被调用。特别是,这是非常不安全的线程。如果结果非常大,那么从调用者不再需要它到下一次调用该函数时,该内存被浪费了。
型号: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 */ }
}
优点:最灵活。
缺点:调用者必须传入足够大的缓冲区(假设cpp_function
行为一致,调用者可以通过调用大小为 0 和空指针的函数来找出大小,从某个地方获取足够大的缓冲区,然后再次调用该函数)。
型号:strcpy
, snprintf
, getaddrinfo
.
#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;
}
您可以将返回的临时向量保存在具有静态存储持续时间的向量对象中。
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]
}
从返回的指针call_foo_and_get_pointer
保证在下一次调用它之前保持有效。