在 Rcpp 中调用 `[data.frame` 子集 data.frame 时避免 SIGSEGV

Avoid SIGSEGV when subsetting data.frame with call to `[data.frame` in Rcpp

由于我不明白的原因,我的 Rcpp 代码偶尔会失败(SEGFAULT 等)。该代码创建一个大 data.frame,然后尝试通过调用 R 子集函数 [.data.frame) 从创建框架的相同方法中获取此 data.frame 的子集。它的一个非常简化的版本如下所示:

library(Rcpp)
src <- '// R function to subset data.frame - what will be called to subset
DataFrame test() {
Function subsetinR("[.data.frame"); 

// Make a dataframe in Rcpp to subset
size_t n = 100;
auto df =  DataFrame::create(Named("a") = std::vector<double> (n, 2.0),
                             Named("b") = std::vector<double> (n, 4.0));

// Now make a vector to subset with 
LogicalVector filter = LogicalVector::create(n, TRUE);
for (size_t i =0; i < n; i++) {
    if (i % 2 == 0) filter[i] = FALSE;
}   

// Subset, here is where it fails!
df = subsetinR(df, filter, R_MissingArg);
return df; 
}'  

fun <- cppFunction(plugins=c("cpp11"), src, verbose = TRUE, depends="Rcpp") 
fun()

然而,虽然这偶尔有效,但有时会失败并出现以下错误:

*** caught segfault ***
   address 0x7ff700000030, cause 'memory not mapped'`

有人知道出了什么问题吗?

注意:这不是重复的。我已经看到其他堆栈溢出答案,它们通过利用每个向量的子集来创建向量,例如

  // Next up, create a new DataFrame Object with selected rows subset. 
  return Rcpp::DataFrame::create(Rcpp::Named("val1")  = val1[idx],
                                 Rcpp::Named("val2")  = val2[idx],
                                 Rcpp::Named("val3")  = val3[idx],
                                 Rcpp::Named("val3")  = val4[idx]
                                 );

但是,我明确希望避免重复 [idx] 子集,因为在构造 data.frame 时不知道 idx(它只在最后才知道),我是希望找到一种不涉及重复调用它的方法。不过,如果最后可以一次转换 data.frame,那就没问题了。

这里的问题是 LogicalVector::create() 没有按照您的预期进行 - 它返回一个长度为 2 的向量,其中包含元素 TRUETRUE。换句话说,您的代码:

LogicalVector filter = LogicalVector::create(n, TRUE);

生成的不是长度为 n 且值为 TRUE 的逻辑向量,而是长度为 2 且第一个元素为 'truthy' 的逻辑向量,因此 TRUE , 第二个明确 TRUE.

您可能只想使用常规构造函数,例如LogicalVector(n, TRUE).