[Rcpp-devel] pointer to c++ object with modules

Romain Francois romain at r-enthusiasts.com
Mon Feb 6 20:09:53 CET 2012


Le 06/02/12 19:40, Chris DuBois a écrit :
> Hi all,
>
> I have a class that stores data and various statistics about my data.  I
> want to be able to work with it from R and from C++ functions, but I do
> not want to have the entire data structure created as an R object.  I
> thought one might be able to return a pointer from the object to R, and
> pass that pointer from R to a C++ function that needs to interact with
> the object.  This seems to work until garbage collection occurs, at
> which point I get a segfault.
>
> I have included an example below illustrating my current approach.  I
> altered the World example to return a pointer to the current object.  I
> have a C++ function that makes changes to the object.
>
> I saw this post
> http://lists.r-forge.r-project.org/pipermail/rcpp-devel/2011-December/003214.html
>   but I wanted to use modules and I haven't been able to adapt that
> solution to my situation.
>
> Any help/advice is much appreciated,
> Chris
>
> library(inline)
> library(Rcpp)
> fx <- cxxfunction(,"",includes=
> '
> #include <Rcpp.h>
>
> class World {
> public:
>    World() : msg("hello") {}
>    void set(std::string msg) {
>      this->msg = msg;
>    }
>    std::string greet() {
>      return msg;
>    }
>    SEXP ptr() {
>      return wrap(XPtr<World>(this, true));
>    }
>
> private:
>    std::string msg;
> };
>
> int fn(SEXP ptr_) {
>    World *s = XPtr<World>(ptr_);
>    s->set("c++ function has been here");
>    return 1;
> }
>
> RCPP_MODULE(example){
> using namespace Rcpp ;
> function("fn", &fn);
> class_<World>( "World")
>    .constructor()
>    .method( "greet", &World::greet ,
> "get the message")
>    .method( "set", &World::set ,
> "set the message")
>    .method( "ptr", &World::ptr ,
> "get a pointer");
> }
> ', plugin="Rcpp")
>
> example <- Module("example",getDynLib(fx))
>
> s <- new(example$World)
>
> # Interact with World object from R
> s$greet()
> s$set("hello from R")
> s$greet()
>
> # Grab pointer to this World object
> s$ptr()
>
> # Call a c++ function that uses World object
> example$fn(s$ptr())
> s$greet()  # c++ function has altered s, as desired
>
> # Causes segfault
> gc()


That's subtle. When you call your ptr function, you create a new R 
external pointer to encapsulate the same underlying C++ pointer. When 
the R external pointer object you created goes out of scope, it becomes 
a candidat for gabage collection. When GC occurs, the undelying pointer 
is delete'd.

You could prevent the finalizer by using :

SEXP ptr() {
     return XPtr<World>(this, false);
   }

Also, you don't need wrap because XPtr has a SEXP operator inherited 
from RObject.

Romain


-- 
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30
R Graph Gallery: http://addictedtor.free.fr/graphiques
blog:            http://romainfrancois.blog.free.fr
|- http://bit.ly/xbKv0R : Crawling facebook with R
|- http://bit.ly/v3WB8S : ... And now for solution 17, still using Rcpp
`- http://bit.ly/uaQDGr : int64: 64 bit integer vectors for R


More information about the Rcpp-devel mailing list