1

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

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

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)

digEmAll
  • 56,430
  • 9
  • 115
  • 140
  • 1
    You do not need to write a VectorWrap, just interface directly with the [`Vector`](http://dirk.eddelbuettel.com/code/rcpp/html/vector_2Vector_8h_source.html) class, which has necessary policy classes setup to protect against garbage collection. The `NumericVector` et al, are all `typedefs` that are run through this class. – coatless Oct 24 '16 at 19:32
  • Yes, I know what you mean, but as I said my example is oversimplified; my real needs are much more complex but my issue (i.e. SEXP protection inside a class wrapped in Xptr) can be simplified with this (obviously stupid) example ;-) – digEmAll Oct 24 '16 at 19:44

1 Answers1

6

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

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.

nrussell
  • 18,382
  • 4
  • 47
  • 60
  • I didn't know of RObject but it seems the perfect solution in this case, thanks! (PS I normally use `{ }` for control flow structures, in this case I just removed them to shorten the post, about `this->` instead I like to use it, but I know many people suggest otherwise...) – digEmAll Oct 24 '16 at 20:29