Избегайте SIGSEGV при настройке data.frame с вызовом `[data.frame` в Rcpp
Мой код Rcpp иногда дает сбой (SEGFAULT и т. Д.) По причинам, которые я не понимаю. Код создает большой data.frame, а затем пытается получить подмножество этого data.frame, вызывая функцию R subset, [.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]
подмножество, поскольку idx неизвестно, когда создается data.frame (он известен только в конце), и я надеюсь найти способ, который не требует повторного вызова этого. Если возможно преобразовать data.frame в конце одним движением, это будет работать просто отлично.
1 ответ
Проблема здесь в том, что LogicalVector::create()
не делает то, что вы ожидаете здесь - он возвращает вектор длины два с элементами TRUE
а также TRUE
, Другими словами, ваш код:
Фильтр LogicalVector = LogicalVector::create(n, TRUE);
генерирует не логический вектор длины n
со значениями TRUE
, но вместо этого логический вектор длины два с первым элементом, являющимся "правдивым" и так TRUE
а второй явно TRUE
,
Вы, вероятно, намеревались просто использовать обычный конструктор, например LogicalVector(n, TRUE)
,