External pointers with Rcpp
One of the new features of Rcpp is the
XPtr class template, which lets you treat an R external pointer as a regular pointer. For more information on external pointers, see Writing R extensions.
To use them, first we need a pointer to some C++ data structure, we'll use a pointer to a
/* creating a pointer to a vector<int> */ std::vector<int>* v = new std::vector<int> ; v->push_back( 1 ) ; v->push_back( 2 ) ;
Then, using the
XPtr template class we wrap the pointer in an R external pointer
/* wrap the pointer as an external pointer */ /* this automatically protected the external pointer from R garbage collection until p goes out of scope. */ Rcpp::XPtr< std::vector<int> > p(v, true) ;
The first parameter of the constructor is the actual (sometimes called dumb) pointer, and the second parameter is a flag indicating that we need to register a delete finalizer with the external pointer. When the external pointer goes out of scope, it becomes subject to garbage collection, and when it is garbage collected, the finalizer is called, which then calls delete on the dumb pointer.
Wrapping it all together thanks to the inline package, here's a function that creates an external pointer to a vector<int> and return it to R
funx <- cfunction(signature(), ' /* creating a pointer to a vector<int> */ std::vector<int>* v = new std::vector<int> ; v->push_back( 1 ) ; v->push_back( 2 ) ; /* wrap the pointer as an external pointer */ /* this automatically protected the external pointer from R garbage collection until p goes out of scope. */ Rcpp::XPtr< std::vector<int> > p(v, true) ; /* return it back to R, since p goes out of scope after the return the external pointer is no more protected by p, but it gets protected by being on the R side */ return( p ) ; ', Rcpp=TRUE, verbose=FALSE) xp <- funx()
At that point,
xp is an external pointer object
> xp <pointer: 0x9c850c8> > typeof( xp )  "externalptr"
Then, we can pass it back to the C(++) layer, an continue to work with the wrapped stl vector of ints. For this we use the other constructor for the
XPtr class template, that takes an R object (SEXP) of sexp type EXTPTRSXP.
/* wrap the SEXP as a smart external pointer */ Rcpp::XPtr< std::vector<int> > p(x) ; /* use p as a 'dumb' pointer */ p->front() ;
Again, we can wrap this up for quick prototyping using the inline package :
# passing the pointer back to C++ funx <- cfunction(signature(x = "externalptr" ), ' /* wrapping x as smart external pointer */ /* The SEXP based constructor does not protect the SEXP from garbage collection automatically, it is already protected because it comes from the R side, however if you want to keep the Rcpp::XPtr object on the C(++) side and return something else to R, you need to protect the external pointer, by using the protect member function */ Rcpp::XPtr< std::vector<int> > p(x) ; /* just return the front of the vector as a SEXP */ return( Rcpp::wrap( p->front() ) ) ; ', Rcpp=TRUE, verbose=FALSE) front <- funx(xp)
> front  1
The example is extracted from one unit tests that we use in Rcpp, see the full example :
> system.file( "unitTests", "runit.XPTr.R", package = "Rcpp" )  "/usr/local/lib/R/library/Rcpp/unitTests/runit.XPTr.R"
See also the announcement for the release of Rcpp 0.7.1 here to get a list of new features, or wait a few days to see version 0.7.2.
Using the XPtr class template is the bread and butter of the CPP package I blogged about here