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

时间:2016-10-24 19:13:47

标签: 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));
}

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")

基本上我将VecWrap向量作为SEXP函数的参数接收到自定义类createVecWrap内,以便稍后使用。

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

1 个答案:

答案 0 :(得分:5)

一般来说,你应该尽可能地坚持使用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的可读性。