当放在 Rcpp::Xptr 中时,SEXP 函数参数是否应该被保护?
Should SEXP function args be PROTECTed when put inside an Rcpp::Xptr?
看看下面的(过于简单的)Rcpp
+ R
代码:
test.cpp :
#include <Rcpp.h>
using namespace Rcpp;
class VecWrap{
public:
SEXP vector;
int type;
VecWrap(SEXP vector)
{
this->vector = vector;
this->type = TYPEOF(vector);
if(this->type != INTSXP && this->type != REALSXP)
stop("invalid type");
}
bool contains(double val){
if(type == INTSXP){
IntegerVector v = vector;
for(int i = 0; i < v.size(); i++)
if(v[i] == val)
return true;
}else if(type == REALSXP){
NumericVector v = vector;
for(int i = 0; i < v.size(); i++)
if(v[i] == val)
return true;
}
return false;
}
};
// [[Rcpp::export]]
SEXP createVecWrap(SEXP x) {
VecWrap* w = new VecWrap(x);
return XPtr< VecWrap >(w);
}
// [[Rcpp::export]]
SEXP vecWrapContains(XPtr< VecWrap > w, double val){
return wrap(w->contains(val));
}
test.R :
library(Rcpp)
sourceCpp(file='test.cpp')
v <- 1:10e7
w <- createVecWrap(v)
vecWrapContains(w, 10000) # it works
# remove v and call the garbage collector
rm(v)
gc()
vecWrapContains(w, 10000) # R crashes (but it works with small vector "v")
基本上我在自定义 class VecWrap
中放入了作为 createVecWrap
函数参数接收的 SEXP
向量,以便稍后使用它。
但是,正如代码中的注释所解释的,如果我从 R 端删除向量 v
并调用垃圾收集器,当我尝试访问该向量时,R 进程会崩溃。
vector 是否应该以某种方式受到 GC 的保护?如果是这样,如何? (如果可能,采用 Rcpp 样式)
一般来说,您应该尽量坚持使用 C++ 类型系统/Rcpp 类(回复:如果可能,避免直接处理 SEXP
)。但是,RObject
class 将为您的 SEXP
提供垃圾收集器的保护,并且在这种情况下似乎有效:
#include <Rcpp.h>
class VecWrap {
public:
Rcpp::RObject vector;
int type;
VecWrap(SEXP vector_)
: vector(vector_)
{
type = vector.sexp_type();
if (type != INTSXP && type != REALSXP) {
Rcpp::stop("invalid type");
}
}
bool contains(double val) {
if (type == INTSXP){
Rcpp::IntegerVector v = Rcpp::as<Rcpp::IntegerVector>(vector);
for (int i = 0; i < v.size(); i++) {
if (v[i] == val) return true;
}
} else if (type == REALSXP) {
Rcpp::NumericVector v = Rcpp::as<Rcpp::NumericVector>(vector);
for (int i = 0; i < v.size(); i++) {
if (v[i] == val) return true;
}
}
return false;
}
};
// [[Rcpp::export]]
Rcpp::XPtr<VecWrap> createVecWrap(SEXP x) {
return Rcpp::XPtr<VecWrap>(new VecWrap(x));
}
// [[Rcpp::export]]
bool vecWrapContains(Rcpp::XPtr<VecWrap> w, double val) {
return w->contains(val);
}
v <- 1:10e7
w <- createVecWrap(v)
vecWrapContains(w, 10000)
# [1] TRUE
rm(v)
gc()
# used (Mb) gc trigger (Mb) max used (Mb)
# Ncells 366583 19.6 750400 40.1 460000 24.6
# Vcells 100559876 767.3 145208685 1107.9 100560540 767.3
vecWrapContains(w, 10000)
# [1] TRUE
不相关:考虑使用 { }
作为控制流结构,不要被 this->
冲昏头脑;这两者都会提高代码 IMO 的可读性。
看看下面的(过于简单的)Rcpp
+ R
代码:
test.cpp :
#include <Rcpp.h>
using namespace Rcpp;
class VecWrap{
public:
SEXP vector;
int type;
VecWrap(SEXP vector)
{
this->vector = vector;
this->type = TYPEOF(vector);
if(this->type != INTSXP && this->type != REALSXP)
stop("invalid type");
}
bool contains(double val){
if(type == INTSXP){
IntegerVector v = vector;
for(int i = 0; i < v.size(); i++)
if(v[i] == val)
return true;
}else if(type == REALSXP){
NumericVector v = vector;
for(int i = 0; i < v.size(); i++)
if(v[i] == val)
return true;
}
return false;
}
};
// [[Rcpp::export]]
SEXP createVecWrap(SEXP x) {
VecWrap* w = new VecWrap(x);
return XPtr< VecWrap >(w);
}
// [[Rcpp::export]]
SEXP vecWrapContains(XPtr< VecWrap > w, double val){
return wrap(w->contains(val));
}
test.R :
library(Rcpp)
sourceCpp(file='test.cpp')
v <- 1:10e7
w <- createVecWrap(v)
vecWrapContains(w, 10000) # it works
# remove v and call the garbage collector
rm(v)
gc()
vecWrapContains(w, 10000) # R crashes (but it works with small vector "v")
基本上我在自定义 class VecWrap
中放入了作为 createVecWrap
函数参数接收的 SEXP
向量,以便稍后使用它。
但是,正如代码中的注释所解释的,如果我从 R 端删除向量 v
并调用垃圾收集器,当我尝试访问该向量时,R 进程会崩溃。
vector 是否应该以某种方式受到 GC 的保护?如果是这样,如何? (如果可能,采用 Rcpp 样式)
一般来说,您应该尽量坚持使用 C++ 类型系统/Rcpp 类(回复:如果可能,避免直接处理 SEXP
)。但是,RObject
class 将为您的 SEXP
提供垃圾收集器的保护,并且在这种情况下似乎有效:
#include <Rcpp.h>
class VecWrap {
public:
Rcpp::RObject vector;
int type;
VecWrap(SEXP vector_)
: vector(vector_)
{
type = vector.sexp_type();
if (type != INTSXP && type != REALSXP) {
Rcpp::stop("invalid type");
}
}
bool contains(double val) {
if (type == INTSXP){
Rcpp::IntegerVector v = Rcpp::as<Rcpp::IntegerVector>(vector);
for (int i = 0; i < v.size(); i++) {
if (v[i] == val) return true;
}
} else if (type == REALSXP) {
Rcpp::NumericVector v = Rcpp::as<Rcpp::NumericVector>(vector);
for (int i = 0; i < v.size(); i++) {
if (v[i] == val) return true;
}
}
return false;
}
};
// [[Rcpp::export]]
Rcpp::XPtr<VecWrap> createVecWrap(SEXP x) {
return Rcpp::XPtr<VecWrap>(new VecWrap(x));
}
// [[Rcpp::export]]
bool vecWrapContains(Rcpp::XPtr<VecWrap> w, double val) {
return w->contains(val);
}
v <- 1:10e7
w <- createVecWrap(v)
vecWrapContains(w, 10000)
# [1] TRUE
rm(v)
gc()
# used (Mb) gc trigger (Mb) max used (Mb)
# Ncells 366583 19.6 750400 40.1 460000 24.6
# Vcells 100559876 767.3 145208685 1107.9 100560540 767.3
vecWrapContains(w, 10000)
# [1] TRUE
不相关:考虑使用 { }
作为控制流结构,不要被 this->
冲昏头脑;这两者都会提高代码 IMO 的可读性。