RCPP передать по ссылке против по значению

Я сделал первый удар по функции Rcpp черезinline и это решило мою проблему со скоростью (спасибо Дирк!): R: замена отрицательных значений на ноль

Первоначальная версия выглядела так:

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

Но когда называетсяcpp_if(p)переписалp с выходом, который был не так, как задумано. Поэтому я предположил, что это проходило по ссылке.

Поэтому я исправил это с помощью следующей версии:

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

Который, казалось, работал. Но теперь исходная версия больше не перезаписывает ввод, когда я перезагружаю его в R (т.е. тот же самый точный код теперь не перезаписывает его ввод):

> 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

Я не единственный, кто пытался повторить это поведение и нашел противоречивые результаты:

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

Что здесь происходит?

 Ari B. Friedman02 июл. 2012 г., 22:21
Пытался отредактировать для наглядности. Я не хочу его перезаписывать. Если это неочевидно, то, я думаю, мне следует публиковать сообщения в списке рассылки, но в противном случае я не хочу беспокоить людей.
 Dirk Eddelbuettel02 июл. 2012 г., 22:10
Можете ли вы переформулировать свой вопрос? Вы или не хотите перезаписывать? Мне кажется, что версия 2 добилась того, что намеревалась сделать ... Кроме того, есть специальный список рассылки, посвященный Rcpp, где вы, вероятно, получите достойные ответы.

Ответы на вопрос(1)

Решение Вопроса

Их ключом является «модель прокси»; -- вашxa на самом деле это та же ячейка памяти, что и у вашего исходного объекта, поэтому вы в конечном итоге меняете свой оригинальный.

Если вы этого не хотите, вы должны сделать одну вещь: (глубокое) копирование с использованиемclone() метод, или, возможно, явное создание нового объекта, в который записывается измененный объект. Второй метод делаетnot Для этого вы просто используете две переменные с разными именами, которые обе являются & quot; указателями & quot; (в смысле модели прокси) к исходной переменной.

Дополнительное осложнение, однако, заключается вimplicit приведение и копирование при передаче вектора 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))

и вот что я вижу:

[email protected]:~/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
[email protected]:~/svn/rcpp/pkg$

Так что действительно важно, передаете ли вы int-to-float или float-to-float.

 04 июл. 2012 г., 02:02
Это хороший улов.
 04 июл. 2012 г., 01:41
Очень интересно. Небольшая подсказка для ясности: не следует ли переопределять после каждого вызова функции, особенно после второго вызова f1? В противном случае это измененный p, который подается в f2 ... верно?
 02 июл. 2012 г., 23:02
Когда ты впервые сталкиваешься с этим, это - скребок головы, но да, это имеет смысл.
 26 февр. 2015 г., 17:33
Это довольно интересно. Думаю, единственный способ узнать это - через отладчик (или вы пишете пакет, как сделал Дирк). Есть ли способ присоединить отладчик к функциям Rcpp? Я думаю о том, как отладчик Visual Studio присоединяет DLL, а затем, когда она нажата, вы можете перейти в код. ,
 Ari B. Friedman02 июл. 2012 г., 22:58
Спасибо, Дирк. Это говорит мне о том, как я должен был написать функцию (и я запишу ее для дальнейшего использования). И я думаю, что неявное приведение и копирование, вероятно, объясняют кажущуюся непоследовательность.

Ваш ответ на вопрос