Rcpp-Modules:理解 .finalizer() 以及为什么它没有被调用
Rcpp-Modules: Understanding .finalizer() and why it doesn't get called
我写了一个名为 RMaxima
的 Rcpp 模块,它在调用构造函数时生成一个子进程。我提出这个问题的动机是,当 R 退出已分配并绑定到名称的函数执行环境时,我需要销毁此 class 的对象。
以下是我的源文件的重要部分:
class RMaxima
{
public:
RMaxima()
{
...
// spawnes child process by instantiating an object
myMaxima = new Maxima(...);
}
~RMaxima()
{
// causes the child process to terminate properly
delete myMaxima;
}
...
private:
Maxima* myMaxima;
};
static void rmaxima_finalizer(RMaxima* ptr)
{
if (ptr)
{
delete ptr;
}
}
RCPP_MODULE(Maxima)
{
class_<RMaxima>("RMaxima")
.constructor()
.method(...)
.finalizer(&rmaxima_finalizer)
;
}
我对 R 中垃圾收集的理解是,当解释器退出环境时,来自该环境的值绑定将被丢弃,并且 R 的垃圾收集会为任何未绑定的值释放内存。
但是,这对于 Rcpp 模块似乎有所不同:如果我调用并退出创建我的 class
实例的函数
foo <- function() {
m <- new(Rmaxima)
...
}
那么,不出所料,m并没有出现在全局环境中。但是,子进程仍然是运行。这意味着我的 class' 析构函数/终结器尚未被调用。但是,当我退出 R 会话或安装相应的自定义包时,它会被调用,在此期间测试加载。
为什么?我怎样才能让它在不同的范围内被破坏? “扩展 R”(钱伯斯出版社,2016 年)给了我一些提示
The Rcpp templated type allows conversions to and from "externalptr"
with computations in the C++ code specialized to the type T of the object referred
to. Templated code can in fact use 3 parameters: type, storage scope and a final-
izer to be called when the object pointed to is deleted. The object returned to R
is in all cases of class and type "externalptr". No information is available about
the parametrized form.
指出 classes 返回为 externalptr
并受到 gc()
的保护,但我没有看到连接,因为对象是 typeof(m)
: S4, 即引用 class.
任何进一步的提示,在哪里阅读这个?
您正在使用 Rcpp 模块,这在某种程度上可以替代您自己使用带有外部指针的东西。 Rcpp 为您提供 Rcpp::XPtr
并且您可以查看一些软件包使用的那些。 (我最喜欢的是快速 GitHub 搜索,如 this one across the 'cran' org that mirrors CRAN - 它显示超过 1k 的代码命中,因此需要进一步分类。)
并且 XPtr
本身似乎在 保证 访问终结器方面存在未解决的问题;我在去年提交了 issue #1108,并计划重新审视这个 'soon'。但是尽管这个问题可能是一个极端案例,但总的来说这似乎是有效的。所以我会研究 XPtr
and/or XPtr
在 CRAN 上使用的两个帮助程序包。
最后,Rcpp 类 是由 John 编写和贡献的扩展。不过,他们还没有看到太多用途。 Rcpp 模块使用相当广泛,您也可以查看示例。
最后,你还可以做一些更简单直接的事情:
- 用一个空的构造函数创建一个 class Foo
- 具有指向 class
的单例的静态指针
- 创建一个
init
方法来设置 class 并让它拥有它需要的内存
- 根据需要有 setter/getter/worker/result 方法
- 创建一个
teardown
方法来释放内存
然后首先调用 init(可能来自包加载),然后是所有工作,然后确保调用拆卸。这是一个远非完美的设计(也许不叫拆解?)但是简单性给了你一个比较。一旦你有了碎片,你就可以在上面建造更奇特的结构。
我写了一个名为 RMaxima
的 Rcpp 模块,它在调用构造函数时生成一个子进程。我提出这个问题的动机是,当 R 退出已分配并绑定到名称的函数执行环境时,我需要销毁此 class 的对象。
以下是我的源文件的重要部分:
class RMaxima
{
public:
RMaxima()
{
...
// spawnes child process by instantiating an object
myMaxima = new Maxima(...);
}
~RMaxima()
{
// causes the child process to terminate properly
delete myMaxima;
}
...
private:
Maxima* myMaxima;
};
static void rmaxima_finalizer(RMaxima* ptr)
{
if (ptr)
{
delete ptr;
}
}
RCPP_MODULE(Maxima)
{
class_<RMaxima>("RMaxima")
.constructor()
.method(...)
.finalizer(&rmaxima_finalizer)
;
}
我对 R 中垃圾收集的理解是,当解释器退出环境时,来自该环境的值绑定将被丢弃,并且 R 的垃圾收集会为任何未绑定的值释放内存。
但是,这对于 Rcpp 模块似乎有所不同:如果我调用并退出创建我的 class
实例的函数foo <- function() {
m <- new(Rmaxima)
...
}
那么,不出所料,m并没有出现在全局环境中。但是,子进程仍然是运行。这意味着我的 class' 析构函数/终结器尚未被调用。但是,当我退出 R 会话或安装相应的自定义包时,它会被调用,在此期间测试加载。
为什么?我怎样才能让它在不同的范围内被破坏? “扩展 R”(钱伯斯出版社,2016 年)给了我一些提示
The Rcpp templated type allows conversions to and from "externalptr" with computations in the C++ code specialized to the type T of the object referred to. Templated code can in fact use 3 parameters: type, storage scope and a final- izer to be called when the object pointed to is deleted. The object returned to R is in all cases of class and type "externalptr". No information is available about the parametrized form.
指出 classes 返回为 externalptr
并受到 gc()
的保护,但我没有看到连接,因为对象是 typeof(m)
: S4, 即引用 class.
任何进一步的提示,在哪里阅读这个?
您正在使用 Rcpp 模块,这在某种程度上可以替代您自己使用带有外部指针的东西。 Rcpp 为您提供 Rcpp::XPtr
并且您可以查看一些软件包使用的那些。 (我最喜欢的是快速 GitHub 搜索,如 this one across the 'cran' org that mirrors CRAN - 它显示超过 1k 的代码命中,因此需要进一步分类。)
并且 XPtr
本身似乎在 保证 访问终结器方面存在未解决的问题;我在去年提交了 issue #1108,并计划重新审视这个 'soon'。但是尽管这个问题可能是一个极端案例,但总的来说这似乎是有效的。所以我会研究 XPtr
and/or XPtr
在 CRAN 上使用的两个帮助程序包。
最后,Rcpp 类 是由 John 编写和贡献的扩展。不过,他们还没有看到太多用途。 Rcpp 模块使用相当广泛,您也可以查看示例。
最后,你还可以做一些更简单直接的事情:
- 用一个空的构造函数创建一个 class Foo
- 具有指向 class 的单例的静态指针
- 创建一个
init
方法来设置 class 并让它拥有它需要的内存 - 根据需要有 setter/getter/worker/result 方法
- 创建一个
teardown
方法来释放内存
然后首先调用 init(可能来自包加载),然后是所有工作,然后确保调用拆卸。这是一个远非完美的设计(也许不叫拆解?)但是简单性给了你一个比较。一旦你有了碎片,你就可以在上面建造更奇特的结构。