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() 只是为了保持示例简单。涉及foobar 的创建、销毁和计算是通过调用libfoo 中的函数来执行的。感谢您提供指向 RODBC 包的指针。

以上是关于R .call() 接口和 EXTPTRSXP:了解 PROTECT/UNPROTECT 与外部分配的对象的主要内容,如果未能解决你的问题,请参考以下文章

Spark_RDD之简单Java函数接口

JVM系列之:JIT中的Virtual Call接口

lapply和do.call有什么区别?

Java call和callback的用法

Runnable接口和Callable接口的区别。

Groovy闭包 Closure ( 闭包调用 与 call 方法关联 | 接口中定义 call() 方法 | 类中定义 call() 方法 | 代码示例 )