我有一堆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已经知道正在使用的对象不需要保护。特别是,这适用于函数参数。
因此,为了进行健全性检查,有人可以告诉我,作者保护传入参数的代码示例是否可以减少?如果是这种情况,我将能够使我的代码更清洁。
答案 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
,而这是需要保护的新对象来自垃圾收集器。