当放入Rcpp :: Xptr时,SEXP函数是否应该被保护?

dig*_*All 1 r rcpp

看下面的(过于简化的)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));
}
Run Code Online (Sandbox Code Playgroud)

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")
Run Code Online (Sandbox Code Playgroud)

基本上我把自定义类放在作为函数参数接收VecWrapSEXP向量中createVecWrap,以便以后使用它.

但是,正如代码中的注释所解释的那样,如果我v从R端移除向量并调用垃圾收集器,则当我尝试访问向量时R进程崩溃.
载体是否应该被GC保护?如果是这样,怎么样?(如果可能的话Rcpp风格)

nru*_*ell 5

一般来说,你应该尽量坚持使用C++类型的系统/ Rcpp类(重新:尽可能避免SEXP直接处理).但是,RObject该类将为您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);
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

不相关:考虑使用{ }您的控制流结构,不要随意使用this->; 这两者都将提高您的代码IMO的可读性.

  • @nrussell的Sage建议,"像往常一样"投票. (2认同)