为什么这个Rcpp函数会改变自己范围之外的变量?

时间:2016-02-16 18:05:42

标签: r rcpp

我正在运行以下来自http://markovjumps.blogspot.com/2011/12/r-array-to-rcpparmadillo-cube.html的示例代码,该示例代码说明了如何将R数组转换为RcppArmadillo多维数据集。代码如下

require(inline)
require(RcppArmadillo)

src <- '
       using namespace Rcpp;

       NumericVector vecArray(myArray);
       IntegerVector arrayDims = vecArray.attr("dim");

       arma::cube cubeArray(vecArray.begin(), arrayDims[0], arrayDims[1], arrayDims[2], false);

       //change one element in the array/cube
       cubeArray(0,0,0) = 518;  

       return(wrap(cubeArray));  
'

readCube = cxxfunction(signature(myArray="numeric"),body=src, plugin="RcppArmadillo")

set.seed(345)
testArray = array(rnorm(8), dim=c(2,2,2))
print(testArray[1,1,1])
# -0.7849082
readCube(testArray)[1,1,1]
# 518
print(testArray)[1,1,1]
# 518

可以看出,testArray已被更改。但是,我不太明白为什么会这样。

我对这个问题进行了一些搜索,并在http://arma.sourceforge.net/docs.html#Cube中找到&#34;使用来自可写辅助(外部)内存的数据创建一个多维数据集,其中ptr_aux_mem是指向内存的指针。默认情况下,多维数据集会分配自己的内存并从辅助内存中复制数据(为了安全起见)。但是,如果copy_aux_mem设置为false,则立方体将直接使用辅助存储器(即不复制);这比较快,但除非你知道自己在做什么,否则会很危险!&#34;

所以我将false改为true,问题就消失了。但是,我仍然感到困惑,因为原始代码创建了一个新的NumericVector vecArray,而vecArray.begin()应该引用该新NumericVector对象的内存而不是函数输入myArray。我觉得更改cubeArray应该只更改vecArray而不是myArray。

1 个答案:

答案 0 :(得分:0)

感谢Dirk,现在我看到了我被困的地方。以下是我自己的解决方案:

可以通过使用clone()或创建新的Armadillo立方体对象来解决问题。这两种解决方案如下:

// Using clone()
src <- '
       using namespace Rcpp;

       NumericVector vecArray(clone(myArray));
       IntegerVector arrayDims = vecArray.attr("dim");

       arma::cube cubeArray(vecArray.begin(), arrayDims[0], arrayDims[1], arrayDims[2], false);

       //change one element in the array/cube
       cubeArray(0,0,0) = 518;  

       return(wrap(cubeArray));  
'

readCube = cxxfunction(signature(myArray="numeric"),body=src, plugin="RcppArmadillo")

// Not using clone()
src <- '
       using namespace Rcpp;

       NumericVector vecArray(myArray);
       IntegerVector arrayDims = vecArray.attr("dim");

       arma::cube cubeArray(vecArray.begin(), arrayDims[0], arrayDims[1], arrayDims[2]);

       //change one element in the array/cube
       cubeArray(0,0,0) = 518;  

       return(wrap(cubeArray));  
'

readCube = cxxfunction(signature(myArray="numeric"),body=src, plugin="RcppArmadillo")

请注意,您不希望使用clone()并同时创建新的多维数据集对象,因为它在内存中效率不高。