Rcpp按参考传递与按值传递

Rcpp按参考传递与按值传递,r,rcpp,R,Rcpp,我通过inline首次尝试了一个Rcpp函数,它解决了我的速度问题(谢谢Dirk!): 初始版本如下所示: library(inline) cpp_if_src <- ' Rcpp::NumericVector xa(a); int n_xa = xa.size(); for(int i=0; i < n_xa; i++) { if(xa[i]<0) xa[i] = 0; } return xa; ' cpp_if <- cxxfunctio

我通过
inline
首次尝试了一个Rcpp函数,它解决了我的速度问题(谢谢Dirk!):

初始版本如下所示:

library(inline)
cpp_if_src <- '
  Rcpp::NumericVector xa(a);
  int n_xa = xa.size();
  for(int i=0; i < n_xa; i++) {
    if(xa[i]<0) xa[i] = 0;
  }
  return xa;
'
cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp")
这似乎奏效了。但现在,当我将其重新加载到R中时,原始版本不再覆盖其输入(即,相同的精确代码现在不会覆盖其输入):

>cpp\u if\u src cpp\u if
>p
[1] -5 -4 -3 -2 -1  0  1  2  3  4  5
>cpp_if(p)
[1] 0 0 0 0 0 0 1 2 3 4 5
>p
[1] -5 -4 -3 -2 -1  0  1  2  3  4  5
我不是唯一一个试图复制这种行为并发现不一致结果的人:


这是怎么回事?

它们的关键是“代理模型”——您的
xa
实际上是与原始对象相同的内存位置,因此您最终更改了原始对象

如果您不想这样做,您应该做一件事:(使用
clone()
方法进行深度复制,或者可能显式创建一个新对象,将修改过的对象写入其中。方法2没有做到这一点,您只需使用两个名称不同的变量,它们都是原始变量的“指针”(在代理模型意义上)

然而,另一个复杂问题是,当您将int向量(从R)传递给NumericVector类型时,隐式强制转换和复制:这将创建一个副本,然后原始类型不再被更改

下面是一个更明确的示例,类似于我在教程或研讨会中使用的示例:

library(inline)
f1 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body='
  Rcpp::NumericVector xa(a);
  int n = xa.size();
  for(int i=0; i < n; i++) {
    if(xa[i]<0) xa[i] = 0;
  }
  return xa;
')

f2 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body='
  Rcpp::NumericVector xa(a);
  int n = xa.size();
  Rcpp::NumericVector xr(a);            // still points to a
  for(int i=0; i < n; i++) {
    if(xr[i]<0) xr[i] = 0;
  }
  return xr;
')

p <- seq(-2,2)
print(class(p))
print(cbind(f1(p), p))
print(cbind(f2(p), p))
p <- as.numeric(seq(-2,2))
print(class(p))
print(cbind(f1(p), p))
print(cbind(f2(p), p))

因此,将int传递给float还是将float传递给float确实很重要。

您能重新表述您的问题吗?您是否要覆盖?在我看来,版本2实现了它设定的目标。。。此外,还有一个专门针对Rcpp的邮件列表,您可能会在其中得到不错的答案。为了清晰起见,请尝试编辑。我不想让它覆盖。如果这是不明显的,那么我想我应该发布到邮件列表,但不想打扰其他人。谢谢德克。这告诉了我应该如何编写函数(我将把它归档以备将来使用)。我认为隐式的演员阵容和复制很可能解释了表面上的不一致性。当你第一次遇到它时,这是一个令人头痛的问题,但是是的,它确实有意义。非常有趣。为了清楚起见,有一个小问题:p不应该在每次函数调用之后重新定义吗?尤其是对f1的第二次调用?否则就是被改变的p被送入f2。。。对吧?这很有趣。我想知道这一点的唯一方法是通过调试器(或者像Dirk那样编写包)。有没有办法将调试器附加到Rcpp函数?我正在考虑一种类似Visual Studio debugger附加dll的方法,当它被命中时,您可以进入代码@adam:gcc/g++已经有几十年的历史了,他们最好的朋友gdb也是。
> cpp_if_src <- '
+   Rcpp::NumericVector xa(a);
+   int n_xa = xa.size();
+   for(int i=0; i < n_xa; i++) {
+     if(xa[i]<0) xa[i] = 0;
+   }
+   return xa;
+ '
> cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp")
> 
> p
 [1] -5 -4 -3 -2 -1  0  1  2  3  4  5
> cpp_if(p)
 [1] 0 0 0 0 0 0 1 2 3 4 5
> p
 [1] -5 -4 -3 -2 -1  0  1  2  3  4  5
library(inline)
f1 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body='
  Rcpp::NumericVector xa(a);
  int n = xa.size();
  for(int i=0; i < n; i++) {
    if(xa[i]<0) xa[i] = 0;
  }
  return xa;
')

f2 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body='
  Rcpp::NumericVector xa(a);
  int n = xa.size();
  Rcpp::NumericVector xr(a);            // still points to a
  for(int i=0; i < n; i++) {
    if(xr[i]<0) xr[i] = 0;
  }
  return xr;
')

p <- seq(-2,2)
print(class(p))
print(cbind(f1(p), p))
print(cbind(f2(p), p))
p <- as.numeric(seq(-2,2))
print(class(p))
print(cbind(f1(p), p))
print(cbind(f2(p), p))
edd@max:~/svn/rcpp/pkg$ r /tmp/ari.r
Loading required package: methods
[1] "integer"
        p
[1,] 0 -2
[2,] 0 -1
[3,] 0  0
[4,] 1  1
[5,] 2  2
        p
[1,] 0 -2
[2,] 0 -1
[3,] 0  0
[4,] 1  1
[5,] 2  2
[1] "numeric"
       p
[1,] 0 0
[2,] 0 0
[3,] 0 0
[4,] 1 1
[5,] 2 2
       p
[1,] 0 0
[2,] 0 0
[3,] 0 0
[4,] 1 1
[5,] 2 2
edd@max:~/svn/rcpp/pkg$