首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >FFI / MemoryPointer内存分配

FFI / MemoryPointer内存分配
EN

Stack Overflow用户
提问于 2012-12-28 16:26:43
回答 2查看 1.5K关注 0票数 4

我一定漏掉了什么。我一直在读关于FFI的文章,似乎对此没有一个明确的答案。假设我有以下C++函数:

代码语言:javascript
复制
extern "C" {
  int ReturnAnArrayOfStrings(const char* arrayOfStrings[]) {
    if( NULL == arrayOfStrings ) return someCharList.size();

    for(auto iter = someCharList.begin(), auto index = 0; iter != someCharList.end(); ++iter, ++index) {
        char* allocatedHere = new char[strlen(*iter)]; // note that this is not freed
        strcpy_s(allocatedHere, strlen(*iter), *iter);
        arrayOfStrings[index] = allocatedHere;
    }

    return someCharList.size();
  }
}

据我所知,如果在FFI中使用它,你需要做的就是:

代码语言:javascript
复制
module SomeDll
  extend FFI::Library
  ffi_lib 'SomeDll.dll'
  attach_function :get_strings, :ReturnAnArrayOfStrings, [:pointer], :int
end

include SomeDll
pointer = FFI::MemoryPointer.new :pointer, get_strings(nil)  # how many strings are there?
get_strings pointer
pointer.get_array_of_string(0).each do |value|
  puts value
end

我的问题是:谁来清理记忆?C++方法正在new*字符,但是永远不会释放它,它能处理这个吗?

提前谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-12-29 05:41:29

Ruby FFI试图在谁拥有内存的问题上保持对称--如果你分配它(即C代码),你必须释放它。相反,如果FFI分配了它,它就可以单独释放它。

您没有发布您的FreeStrings()函数,但假设它看起来有点像:

代码语言:javascript
复制
void FreeStringArray(char **strings, int len) {
    for (int i = 0; i < len; ++i) {
        delete[] strings[i];
    }
    // Do _NOT_ free 'strings' itself, that is managed by FFI
}

你可以这样使用它:

代码语言:javascript
复制
module SomeDll
  extend FFI::Library
  ffi_lib 'SomeDll.dll'
  attach_function :get_strings, :ReturnAnArrayOfStrings, [:pointer], :int
  attach_function :free_strings, :FreeStringArray, [ :pointer, :int ], :void
end

include SomeDll

count = get_strings(nil)
strings = FFI::MemoryPointer.new :pointer, count
get_strings strings
strings.get_array_of_string(0, count).each do |value|
  puts value
end

# free each element of the array
free_strings(strings, count)

那么这应该是可行的。

等效的C代码为:

代码语言:javascript
复制
int count = ReturnArrayOfStrings(NULL);

// Allocate an array for the pointers.  i.e. FFI::MemoryPointer.new :pointer, count
char **ptr_array = (char **) calloc(count, sizeof(char *));

ReturnArrayOfStrings(ptr_array);
for (int i = 0; i < count; ++i) {
    printf("string[%d]=%s\n", i, ptr_array[i]);
}

// Free each element of the array (but not the array itself)
FreeStringArray(ptr_array, count);

// free the array itself. i.e FFI::MemoryPointer garbage-collecting its  memory
free(ptr_array);
票数 5
EN

Stack Overflow用户

发布于 2012-12-28 17:37:03

我认为在许多ffi中,无论您使用哪种语言,内置类型(如字符串)的值都必须使用专门提供的运行时函数来构造。Ruby遵守以下规则:

有关该问题的快速教程,请参阅该语言的作者提供的该语言1.8版的article

如果您坚持在代码中分配数据块(使用C++或纯C语言)-毕竟这就是使用该扩展的意义所在-最安全的方法可能是用结构包装它,并使用ffi提供的所谓托管结构工具将dispose函数与数据挂钩(您也必须编写该函数),这样一旦不再需要数据,ruby就知道如何释放数据。但您也可以简单地将数据声明为ruby中的指针(看起来您就是这么做的),并要求userland显式地释放该数据(再次使用extention提供的dispose函数)。

下面的another page演示了托管结构的用法。

最后,不要忘记限定任何你想要作为extern "C"导出到ruby的C++函数(如果你还没有这样做的话)。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14066708

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档