以下代码在R(3.0.2中执行但是我假设它与其他版本类似)时可重复地出现段错误:
ns = new.env(parent = .BaseNamespaceEnv)
local(f <- function () 42, envir = ns)
x = list2env(as.list(ns), parent = as.environment(2))
parent.env(.GlobalEnv) = x
detach()
是的,我知道documentation on parent.env
说
替换函数
parent.env<-
非常危险,因为它可以用于以违反内部C代码假设的方式破坏性地更改环境。它可能会在不久的将来被删除。
这就是我在这里遇到的情况。但是,我想了解为什么这种行为就是这样,以及如何避免它。
以下简化代码不会出现此问题:
x = new.env(parent = as.environment(2))
local(f <- function () 42, envir = x)
parent.env(.GlobalEnv) = x
detach()
...因此,x
包含parent.env
是不同的(未附加)环境的函数似乎有所不同。
同样,使用attach
代替parent.env<-
不会导致崩溃。 (那么为什么不简单地使用attach
?因为在我的代码中,.GlobalEnv
部分是一个可能引用不同环境的变量。)
崩溃转储告诉我,段错误发生在do_detach
(envir.c
)。该代码包含以下行:
isSpecial = IS_USER_DATABASE(s);
if(isSpecial) {
R_ObjectTable *tb = (R_ObjectTable*) R_ExternalPtrAddr(HASHTAB(s));
if(tb->onDetach) tb->onDetach(tb);
}
我不知道IS_USER_DATABASE
做了什么 - 也许这是相关的?仅仅在我的环境中添加.onDetach
方法(.onDetach = function (x) x
)并没有帮助。
答案 0 :(得分:1)
注意:这不是一个评论而是一个真实的答案,但不能在评论字段中使用它。我有一个 loosely related question ,一直在努力更好地理解parent.env<-
的限制。
在您的情况下,请注意问题实际上与list2env
有关,而不是函数。考虑:
f.1 <- function() NULL
ns.1 <- new.env(parent = .BaseNamespaceEnv)
x.1 <- new.env(parent = as.environment(2))
environment(f.1) <- ns.1
x.1$f.1 <- f.1
parent.env(.GlobalEnv) <- x.1
detach()
工作,但是:
x.2 <- list2env(list(a=1), parent=as.environment(2))
parent.env(.GlobalEnv) <- x.2
detach()
崩溃。在这里,除了用list2env
创建的环境之外,我们甚至没有对我们作为父级使用的环境做任何复杂的事情。查看来源我不明白为什么list2env
是一个问题,但$<-
不是因为内部似乎都使用defineVar
,但显然有很多去那里,我不明白。
答案 1 :(得分:0)
为了完整起见,明显的解决方法是测试环境是否为.GlobalEnv
,以及特殊情况:
new_env = something # e.g. .GlobalEnv
if (identical(new_env, .GlobalEnv))
attach(x)
else {
parent.env(x) = parent.env(new_env)
parent.env(new_env) = x
}
...但这并不是解释最初的错误,我担心,只会隐藏问题而不是删除它。