是否有必要保护.Call参数?

时间:2016-09-30 12:28:12

标签: c r

我有一堆Rcpp代码,我必须重写为Rcpp免费的C / C ++扩展(由于它的许可证),幸运的是它并没有像我担心的那样痛苦。但为了编写最干净的代码,我想确保我不会过度使用PROTECT / UNPROTECT。 Writing R Extensions医生提到了#34;然后保护视线中的所有内容并不是一个好主意..."所以我试图尽职尽责。

所以我想检查一下。在阅读为R编写C扩展的所有示例时,我已经看到许多示例,其中作者保护传递函数的参数,例如从this article获取。

#include <R.h>
#include <Rdefines.h>
#include <string.h>
SEXP helloC1(SEXP greeting) {
  int i, vectorLength, stringLength;
  SEXP result;
  PROTECT(greeting = AS_CHARACTER(greeting));
  vectorLength = LENGTH(greeting);
  PROTECT(result = NEW_INTEGER(vectorLength));
  for (i=0; i<vectorLength; i++) {
    stringLength = strlen(CHAR(STRING_ELT(greeting, i)));
    INTEGER(result)[i] = stringLength;
  }
  UNPROTECT(2);
  return(result);
}

SEXP问候语作为参数传递,作者立即保护它。但是,从Writing R Extensions我注意到了这一点:

  

R已经知道正在使用的对象不需要保护。特别是,这适用于函数参数。

因此,为了进行健全性检查,有人可以告诉我,作者保护传入参数的代码示例是否可以减少?如果是这种情况,我将能够使我的代码更清洁。

2 个答案:

答案 0 :(得分:9)

  

我有一堆Rcpp代码,我必须重写为无Rcpp的C / C ++扩展(由于其许可证)

您可能需要(更好)的律师。 R本身与Rcpp的许可证相同,因此&#34;避免&#34;由于链接聚合仍然是GPL 2或更高版本,Rcpp对你的影响很小。

编辑:而且只是为了踢,这里有两个更简单,更短的函数实现。您可能会发现它们更易于阅读和使用。用户空间没有PROTECT跳舞,因为Rcpp负责这一切。

#include <Rcpp.h>

using namespace Rcpp;

// [[Rcpp::export]]
IntegerVector  helloC2(CharacterVector v) {
  IntegerVector res(v.size());
  for (int i=0; i<v.size(); i++) {
    res[i] = strlen(v[i]);
  }
  return(res);
}

// [[Rcpp::export]]
IntegerVector  helloC3(CharacterVector v) {
  return wrap(sapply(v, strlen));
}

它们(当然)产生相同的函数输出。

首先,你的:

R> system("cd /tmp && R CMD SHLIB prot.c")
R> dyn.load("/tmp/prot.so")
R> .Call("helloC1", c("the", "quick", "brown", "fox"))
[1] 3 5 5 3
R> 

接下来,我的:

R> Rcpp::sourceCpp("/tmp/prot.cpp")
R> helloC2(c("the", "quick", "brown", "fox"))
[1] 3 5 5 3
R> helloC3(c("the", "quick", "brown", "fox"))
[1] 3 5 5 3
R> 

答案 1 :(得分:4)

输入参数不需要保护,但你误解了一点 - 它不是被保护的输入参数greeting,而是由SEXP生成的新AS_CHARACTER(greeting)这是受到保护的。

这有点令人困惑,因为greeting变量会立即重新分配,但实际上您现在greeting指向一个全新的SEXP,而这是需要保护的新对象来自垃圾收集器。