Rcpp übergeben als Referenz vs. nach Wert

Ich machte einen ersten Stich über eine Rcpp-function über inline und triggerse mein Geschwindigkeitsproblem (Danke Dirk!): R: Negative Werte durch Null ersetzen

Die ursprüngliche Version sah so aus:

 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") 

Aber wenn cpp_if(p) aufgerufen wurde, hat es p mit der Ausgabe cpp_if(p) , was nicht wie vorgesehen war. Also nahm ich an, dass es als Referenz weitergegeben wurde.

Also habe ich es mit der folgenden Version behoben:

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

Was zu funktionieren schien. Aber jetzt überschreibt die ursprüngliche Version ihre Eingabe nicht mehr, wenn ich sie in R neu lade (dh derselbe exakte Code überschreibt jetzt nicht seine Eingabe):

 > cpp_if_src <- ' + Rcpp::NumericVector xa(a); + int n_xa = xa.size(); + for(int i=0; i < n_xa; i++) { + if(xa[i] cpp_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 

Ich bin nicht der Einzige, der versucht hat, dieses Verhalten nachzubilden und inkonsistente Ergebnisse zu finden:

http://chat.stackoverflow.com/transcript/message/4357344#4357344

Was ist denn hier los?

   

    Der Schlüssel ist “Proxy-Modell” – Ihr xa wirklich der gleiche Speicherort wie Ihr Original-Objekt, so dass Sie am Ende Ihr Original ändern.

    Wenn Sie das nicht wollen, sollten Sie eine Sache tun: (tief) kopieren Sie mit der clone() Methode oder vielleicht explizite Erstellung eines neuen Objekts, in das das geänderte Objekt geschrieben wird. Methode zwei tut das nicht , Sie verwenden einfach zwei unterschiedlich benannte Variablen, die beide “pointers” (im Sinne des Proxy-Modells) für die ursprüngliche Variable sind.

    Eine zusätzliche Komplikation besteht jedoch impliziten Cast und Copy, wenn Sie einen Int-Vektor (von R) an einen NumericVector-Typ übergeben: das erstellt eine Kopie, und dann wird das Original nicht mehr geändert.

    Hier ist ein expliziteres Beispiel, ähnlich dem, das ich in den Tutorials oder Workshops verwende:

     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)) 

    und das sehe ich:

     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$ 

    Es ist also wichtig, ob Sie Int-zu-Float oder Float-Float übergeben.