将 SEXP 函数 args 放入 Rcpp::Xptr 时是否应该受到保护? [英] Should SEXP function args be PROTECTed when put inside an Rcpp::Xptr?

查看:48
本文介绍了将 SEXP 函数 args 放入 Rcpp::Xptr 时是否应该受到保护?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

看看下面的(过度简化的)Rcpp + R 代码:

Look at the (oversimplified) Rcpp + R code below :

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

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

Basically I put inside the custom class VecWrap the SEXP vector received as argument of createVecWrap function, in order to use it later.

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

But, as explained by the comments in the code, if I remove the vector v from the R-side and call the garbage collector, the R process crashes when I try to access the vector.
Should the vector be protected by the GC in someway ? If so, how? (Rcpp-style if possible)

推荐答案

一般来说你应该尽量坚持 C++ 类型系统/Rcpp 类(re:避免直接处理 SEXP如果可能的话).但是,Rcppcode> 类 将为您的 SEXP 提供垃圾收集器的保护,并且在这种情况下似乎有效:

Generally speaking you should try to stick to the C++ type system / Rcpp classes as much as possible (re: avoid handling SEXP directly if possible). However, the RObject class will provide your SEXP with protection from the garbage collector, and seems to work in this case:

#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 代码的可读性.


Unrelated: consider using { } for your control flow structures, and don't get carried away with this->; both of those will improve the readability of your code IMO.

这篇关于将 SEXP 函数 args 放入 Rcpp::Xptr 时是否应该受到保护?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆