在 C++ 函数环境中删除输入 R 对象

use*_*927 5 c++ r rcpp

我在 R 函数中有一个 Rcpp 函数。R 函数生成一些对象(比如一个大列表)并将其提供给 Rcpp 函数。在 Rcpp 函数中,我处理 R 对象,将结果加载到多个 C++ 类中。现在 R 对象变得无用了。我想清除 R 对象,为主要算法创建一个内存充足的环境。

这个想法是:

// [[Rcpp::export]]
void cppFun(List structuredData)
{
  // copy structuredData to C++ classes
  // Now I want structuredData gone to save memory
  // main algorithms ...
}

/***R
rFun(input)
{
  # R creates structuredData from input
  cppFun(structuredData)
}
*/
Run Code Online (Sandbox Code Playgroud)

我尝试在 C++ 中调用 R 的“rm()”,但它只能识别 R 全局环境中的对象名称。例如:

// [[Rcpp::export]]
void cppFun()
{
  Language("rm", "globalDat").eval(); 
  Language("gc").eval();
}

/***R
globalDat = 1:10
ls() # shows "globalDat" is created.
cppFun() # shows "globalDat" is no longer in the environment.
ls()
*/
Run Code Online (Sandbox Code Playgroud)

但是,以下方法不起作用:

// [[Rcpp::export]]
void cppFun()
{
  Language("rm", "localDat").eval(); 
  Language("gc").eval();
}

/***R
rFun <- function (x)
{
  locDat = x
  ls() //  shows "x" and "locDat" are created
  cppFun()
  ls()
}

globalDat = 1:10
ls() # shows "globalDat" is created.
rFun(globalDat) # it will print "x","locDat" twice and a warning message: In rm("localDat") : object 'localDat' not found

locDat = globalDat
rFun(globalDat) # this will still remove "locDat" from the global environment.
*/
Run Code Online (Sandbox Code Playgroud)

我是否走在通往目标的正确轨道上?有没有更好的办法?

谢谢!

想到一个hacky解决方案:

  1. 编写一个封装对所有必需的 C++ 结构化数据类的引用的 shell 类。

  2. 在R函数中,(i)处理输入;(ii) 将结构化的 R 数据提供给 Rcpp 函数;(iii) 在Rcpp函数中,new一个shell类对象,加载结构化的R数据;(iv)memcpy指向 a 的 shell 类指针double(8 字节,如果是 32 位系统,则使用int);(v) 返回double;(vi) 返回doubleR 函数的输出。现在结构化的 R 对象死了,而newed C++ shell 对象仍然存在。呼吁gc()垃圾收集。

  3. 将 提供double给主 C++/Rcpp 函数。memcpy这个 double 指向一个 shell 类指针。delete函数返回前的 shell 类指针。

测试显示了上述工作。刚刚找到“外部指针”或Rcpp::XPtr为类似目的而设计?

coa*_*ess 6

Rcpp 中,按照这些方式做某事将被称为反模式,或高度适得其反。为什么这是有问题的,因为Rcpp在将R对象移动到C++时执行浅拷贝,这意味着R对象与实例化的C++对象共享它的内存分配。如果要删除ř对象而C ++对象的引用,那么你可能会遇到麻烦在后面的过程为分段故障(段错误)将可能发生。

现在,如果你打算做一个深拷贝[R对象转换为C ++结构,这不会是非常有毒。在做深层副本,数据也不会引用原始[R对象。但是,这不是Rcpp的默认架构。

话虽如此,我强烈不鼓励在过程中删除对象。如果您确实内存不足,请尝试“分块”/更多地分割数据、使用数据库执行操作、购买额外的 RAM 或等待ALTREP.