R .call() 接口和 EXTPTRSXP:了解 PROTECT/UNPROTECT 与外部分配的对象
Posted
技术标签:
【中文标题】R .call() 接口和 EXTPTRSXP:了解 PROTECT/UNPROTECT 与外部分配的对象【英文标题】:R .call() interface and EXTPTRSXP: Understanding PROTECT/UNPROTECT with externally allocated objects 【发布时间】:2011-10-09 01:59:12 【问题描述】:在以下代码中,通过调用 foo_new() 创建 foo 类型的对象,并将指向该对象的外部指针返回给 R。通过传递 ptr_foo 执行后续计算。对象最终通过显式调用 foo_free(foo *X) 被释放。所有计算都由 libfoo 执行。
创建 ptr_foo 是否意味着 foo 对象中的所有其他动态分配的字段都被自动保护?或者,“bar”之类的字段有没有可能被垃圾收集器扫走?
SEXP foo_new (SEXP n)
SEXP ptr_foo;
foo *X = (foo*) foo_new( 1, sizeof(foo) );
//foo is protected from garbage collection
assert( X );
X->bar = (int*) foo_add_bar(INTEGER_VALUE(n));
//Is bar protected from garbage collection?
assert(X->bar);
PROTECT( ptr_foo = R_MakeExternalPtr(X, install("extptr_foo"), R_NilValue) );
R_RegisterCFinalizerEx( ptr_foo, ptr_foo_finalize, 1 );
UNPROTECT( 1 );
return (ptr_foo);
谢谢,
RT
【问题讨论】:
【参考方案1】:看起来你的 foo 对象是你自己创造的(不是和 SEXP)。如果是这样,它与 R 无关,也不是垃圾收集,因此不需要/不能受到保护。除了你,没有人会看它或它的领域。
您放入其中的 bar 对象也是您自己创建的,而不是我假设的 R 对象(SEXP)。如果它是 SEXP 或指向 SEXP 中的数据,则需要保护该数据。一个更安全/更简单的方法是复制 SEXP 中的数据。
当 R 不再使用 ptr_foo 对象并进行垃圾回收时,您的 ptr_foo_finalize 函数将被调用以删除您的 foo 对象(和 bar 部分)。
【讨论】:
谢谢汤米。这就是我所希望的。正如您所指出的,R 和 libfoo 之间的所有数据交换都是通过将 SEXP 复制进出进行的。库分配的所有对象都被 foo_free() 调用释放。【参考方案2】:对于初学者,您不应该对 R 对象使用 calloc()
或 malloc()
,“编写 R 扩展”手册对此非常清楚。
其次,每个分配都会得到自己的 PROTECT all。
第三,外部指针对象是在其他地方创建的东西的 R 表示(有关规范的示例,请参阅 RODBC 包及其 DB 接口的实现)。我认为您不应该从内部创建外部指针对象。
【讨论】:
感谢 Dirk,我编辑了我的原始代码。我使用calloc()
只是为了保持示例简单。涉及foo
和bar
的创建、销毁和计算是通过调用libfoo
中的函数来执行的。感谢您提供指向 RODBC 包的指针。以上是关于R .call() 接口和 EXTPTRSXP:了解 PROTECT/UNPROTECT 与外部分配的对象的主要内容,如果未能解决你的问题,请参考以下文章
Groovy闭包 Closure ( 闭包调用 与 call 方法关联 | 接口中定义 call() 方法 | 类中定义 call() 方法 | 代码示例 )