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
_______________________________________________
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel

Reply via email to