soeren.vogel at uzh.ch
2011-May-06 17:24 UTC
[Rd] Create and access several instances of a C++ class from R
Hello We have a C++ class with several methods that manipulate an object. How is it possible to create several instances of that class *from R* in the C++ realm, which can then be accessed via a given name character? Symbolic example (we hope this illustrates our problem): // C++ side: class Foo{ ... } // perhaps: void my_new_instance_wrapper("the_character") // plain to see that I am no C++ programmer ;-) { static Foo "the_character"; // no return needed since we know the name of the instance = "the_character" } # R side: create_new_instance <- function(name){ dono_what_to_use_here(???, class) } # perhaps: create_new_instance <- function(name){ .C("my_new_instance_wrapper", as.character(name)) } dyn.load("Foo") obj1 <- create_new_instance("bar", class="Foo") obj2 <- create_new_instance("baz", class="Foo") str(obj1) : character which can be manipulated using class methods in the C++ realm What we do not want: make simple copies of the object in R; use Rcpp modules (we tried that without success, pointers in constructors cause trouble); re-write our code such that C++ only "works off" heavy code, the rest is R-side. What we want: interfacing (from the R-side) instances of our class where the instances exist in the C++ realm. Either there is a function (or code) in R that solve this task, perhaps by returning pointers to instances of C++ classes. (Or there is a possibility to create a wrapper in C++ creating a new instance, the wrapper we do not know of.) Thanks for any notes, tips, experiences. S?ren and Carlo
Dirk Eddelbuettel
2011-May-07 00:39 UTC
[Rd] Create and access several instances of a C++ class from R
S?ren and Carlo, On 6 May 2011 at 19:24, soeren.vogel at uzh.ch wrote: | Hello | | We have a C++ class with several methods that manipulate an object. How is | it possible to create several instances of that class *from R* in the C++ | realm, which can then be accessed via a given name character? Yes it is, and even somewhat easily given Rcpp modules as we tried to explain over at the Rcpp-devel list when you asked there. As a real quick proof-of-concept, I did the following: 1) Make sure you have a recent Rcpp such as 0.9.3 or 0.9.4 2) Let Rcpp create a complete 'stub' of a working package with Rcpp modules support for you via the Rcpp.package.skeleton.function() with the module=TRUE argument: R> library(Rcpp) R> Rcpp.package.skeleton("simple", module=TRUE) Creating directories ... Creating DESCRIPTION ... Creating NAMESPACE ... Creating Read-and-delete-me ... Saving functions and data ... Making help files ... Done. Further steps are described in './simple/Read-and-delete-me'. Adding Rcpp settings >> added RcppModules: yada >> added Depends: Rcpp >> added LinkingTo: Rcpp >> added useDynLib directive to NAMESPACE >> added Makevars file with Rcpp settings >> added Makevars.win file with Rcpp settings >> added example header file using Rcpp classes >> added example src file using Rcpp classes >> added example R file calling the C++ example >> added Rd file for rcpp_hello_world >> copied the example module R> 3) As you are keen to see that we get actual new objects, I am just doing the minimal code for by adding one for a new class member function: void showmyaddress() const { std::cout << "Address is " << this << std::endl; } which I add to the class 'World' in file simple/src/rcpp_module.rcpp -- on line 32 if it matters. I also add this line to the module definition in the same file on line 62: .const_method( "showmyaddress", &World::showmyaddress, "get *this ptr address") It doesn't matter that the method is const, you can do without const in both eg void showmyaddress() { std::cout << "Address is " << this << std::endl; } .method( "showmyaddress", &World::showmyaddress, "get *this ptr address") All that the code does is reveal its pointer to stdout. 4) Install it via $ R CMD INSTALL simple 5) Try it in R (and I first R> library(simple) Loading required package: Rcpp R> World C++ class 'World' <0x2b84940> Constructors: World() Fields: No public fields exposed by this class Methods: std::string greet() docstring : get the message void set(std::string) docstring : set the message void showmyaddress() const docstring : get *this ptr address R> R> w1 <- new( World ) R> w1$showmyaddress() Address is 0x2748370 R> R> w2 <- new( World ) R> w2$showmyaddress() Address is 0x2f960b0 R> so w1 and w2 are indeed objects of class World which live in different memory locations. This should show the mechanics. This is somewhat easy -- especially if you know some C++ where it then helps you from having to write boiler plate code. If you are relatively new to C and C++, it can be a little tougher. Either way, to my mind it is shorter (and I'd argue, easier) than anything you could do in plain C with the standard R API. Good luck, and please bring Rcpp questions to rcpp-devel. Regards, Dirk | Symbolic example (we hope this illustrates our problem): | | // C++ side: | class Foo{ | ... | } | // perhaps: | void my_new_instance_wrapper("the_character") // plain to see that I am no C++ programmer ;-) | { | static Foo "the_character"; // no return needed since we know the name of the instance = "the_character" | } | | # R side: | create_new_instance <- function(name){ | dono_what_to_use_here(???, class) | } | # perhaps: | create_new_instance <- function(name){ | .C("my_new_instance_wrapper", as.character(name)) | } | | dyn.load("Foo") | obj1 <- create_new_instance("bar", class="Foo") | obj2 <- create_new_instance("baz", class="Foo") | str(obj1) | : character which can be manipulated using class methods in the C++ realm | | What we do not want: make simple copies of the object in R; use Rcpp modules (we tried that without success, pointers in constructors cause trouble); re-write our code such that C++ only "works off" heavy code, the rest is R-side. What we want: interfacing (from the R-side) instances of our class where the instances exist in the C++ realm. | | Either there is a function (or code) in R that solve this task, perhaps by returning pointers to instances of C++ classes. (Or there is a possibility to create a wrapper in C++ creating a new instance, the wrapper we do not know of.) | | Thanks for any notes, tips, experiences. | | S?ren and Carlo | | ______________________________________________ | R-devel at r-project.org mailing list | https://stat.ethz.ch/mailman/listinfo/r-devel -- Gauss once played himself in a zero-sum game and won $50. -- #11 at http://www.gaussfacts.com