我有一个Rcpp函数,它接受一个S4光栅对象,将一些数据插入一个插槽,然后返回该对象的新版本。这是一个最小的代表:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::S4 new_raster(Rcpp::S4 raster, int n_elem) {
Rcpp::S4 r_data(raster.slot("data"));
r_data.slot("values") = Rcpp::NumericVector(n_elem);
// Need help with...
// creating armadillo vector from `r_data.slot("values")` here
// arma::vec new_data = ... ?
return raster;
}
/*** R
library("raster")
r <- raster(res = 0.1)
n <- ncell(r)
r1 <- new_raster(r, n)
head(r1@data@values)
*/
由于返回的数据可能非常大,我想避免创建多个矢量副本。如何在raster@data@values
插槽中创建犰狳矢量而不复制?
答案 0 :(得分:4)
编辑:我没有正确理解这个问题。目标是从S4对象中提取信息并与Armadillo对象共享该内存。我将离开这个答案的第一部分,因为它仍然具有优点,因为它突出了如何重用Armadillo对象内存并重新分配给NumericVector
。尽管如此,第二部分可能更为相关,因为在Noam的回应之后,现在问题已经明确了。
如果我正确理解了这个问题,目标是重用已分配给初始Armadillo向量的存储位置(例如零填充)。根据评论的子目标是稍后将其移至NumericVector
。
所以,我们走了:
#include<RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::NumericVector vec_mem_ex(int n_elem) {
// Make the initial vector
arma::vec X(n_elem, arma::fill::zeros);
// Create a new vector
arma::vec Y(X.begin(), X.n_elem, false, true);
// `copy_aux_mem` is set to false, the vector will instead directly
// use the auxiliary memory (ie. no copying).
// This is dangerous in certain circumstances!
// `strict` is set to true, the vector will be bound to the
// auxiliary memory for its lifetime; the number of elements
// in the vector can't be changed
// Show memory is shared by modifying value
Y.fill(42.0);
// Convert X to a NumericVector
Rcpp::NumericVector Z = Rcpp::NumericVector(X.begin(), X.end());
return Z;
}
/***R
(a = vec_mem_ex(5))
*/
这给出了:
> (a = vec_mem_ex(5))
[1] 42 42 42 42 42
要捕获问题的S4
- 并通过@noam-ross'答案给出更新,请考虑以下事项:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::S4 new_raster(Rcpp::S4 raster, int n_elem) {
// Embed S4 object for nesting
Rcpp::S4 r_data(raster.slot("data"));
// Create obj@data@values
// Initializes values with a vector of 0's.
r_data.slot("values") = Rcpp::NumericVector(n_elem);
// --- The new part...
// We do _not_ have access to the vector that was stored in r_data.slot("values")
// Convert from SEXP to NumericVector
Rcpp::NumericVector temp = Rcpp::NumericVector(r_data.slot("values"));
// Use the advanced vector ctor of Armadillo to capture the memory location
arma::vec new_data(
temp.begin(), // Uses the iterator interface to access the double* requirement
n_elem, // Set the size of the vector
false, // Avoid copying by disabling `copy_aux_mem`
true // Bind memory by enabling `strict`
);
// Show memory is shared by modifying value
new_data.fill(42.0);
// --- End new
return raster;
}
/*** R
library("raster")
r <- raster(res = 0.1)
n <- ncell(r)
r1 <- new_raster(r, n)
head(r1@data@values)
*/
答案 1 :(得分:1)
我通过向插槽分配一个空的但是正确大小的NumericVector来解决这个问题,然后在其上调用as()
以找到使用高级Armadillo构造函数的内存指针,如@DirkEddelbuettel和@coatless建议的那样。
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
Rcpp::S4 new_raster(Rcpp::S4 raster, int n_elem) {
Rcpp::S4 r_data(raster.slot("data"));
r_data.slot("values") = Rcpp::NumericVector(n_elem);
arma::vec new_data(
Rcpp::as<Rcpp::NumericVector>(r_data.slot("values")).begin(),
n_elem, false, true
);
new_data.randn();
return raster;
}
/*** R
library("raster")
r <- raster(res = 0.1)
n <- ncell(r)
r1 <- new_raster(r, n)
head(r1@data@values)
*/
结果:
#>[1] -0.26417159 -0.89250080 2.02276338 2.01164847 0.45227281 -0.09313601