I the past days I have been experimenting with how to use R as an interface to an C++ library. I have made a small test package in R that show how it can be done. The idea is to be able to create a C++ object from R and call methods of the C++ class from R before freeing the object from memory in R.
The package/function description goes as follows:
Description
Show how to create C++ objects with external pointers from R which are deleted automatically from R.
Usage
createFoo(str) getStrFoo(p) setStrFoo(p, str) .closeFoo(p)
Arguments
str |
Character string. |
p |
Pointer to Foo object. |
Details
This package shows how to create C++ objects from R which are stored in memory until they are deleted form R. The idea is to be able to call methods of the C++ class before freeing the object from memory. createFoo
create an object of class Foo. getStrFoo
returns the string stored in Foo. setStrFoo
set the string in Foo. .closeFoo(p)
is the internal function used to free the object from memory.
Have a look in the src folder to see how the C and C++ code are made.
The test package is inspired by the “Interfacing C++ code” section in the R extensions manual [1] and Luke Tierney’s page about simple references with finalization [2].
Value
createFoo
returns a pointer to the object of class Foo created in memory. getStrFoo
returns the string stored in Foo. setStrFoo
returns NULL. .closeFoo(p)
return NULL.
Note
Use the extension .cc and .hh for C++ files in the src folder. If you use the extension .c and .h the source code will be compiled using gcc instead of g++!
References
[1] R Development Core Team. Writing R Extensions. Version 2.8.1 (2008-12-22) R Foundation for Statistical Computing, Vienna, Austria. ISBN 3-900051-11-9, http://www.R-project.org.
[2] Simple References with Finalization http://www.stat.uiowa.edu/~luke/R/simpleref.html.
Examples
## Must be run in R from command line in windows. ## Otherwise you will not see the output of cout! # Creating an object p<-createFoo("Testing 1") getStrFoo(p) setStrFoo(p,"Testing 2") getStrFoo(p) trace(.closeFoo) rm(p) # remove the object when the garbage collector is called gc() # Creating two objects p1<-createFoo("Testing 1") p2<-createFoo("Testing 2") getStrFoo(p1) getStrFoo(p2) rm(p1) rm(p2) gc()
The output of running the example becomes
> # Creating an object > p<-createFoo("Testing 1") Constructor Foo called > getStrFoo(p) [1] "Testing 1" > setStrFoo(p,"Testing 2") > getStrFoo(p) [1] "Testing 2" > trace(.closeFoo) > rm(p) # remove the object when the garbage collector is called > gc() trace: function (p) { .Call("TESTCPP_closeFoo", p) }( ) Destructor Foo called used (Mb) gc trigger (Mb) max used (Mb) Ncells 107671 2.9 350000 9.4 350000 9.4 Vcells 74957 0.6 786432 6.0 354231 2.8 > > # Creating two objects > p1<-createFoo("Testing 1") Constructor Foo called > p2<-createFoo("Testing 2") Constructor Foo called > getStrFoo(p1) [1] "Testing 1" > getStrFoo(p2) [1] "Testing 2" > rm(p1) > rm(p2) > gc() trace: function (p) { .Call("TESTCPP_closeFoo", p) }( ) Destructor Foo called trace: function (p) { .Call("TESTCPP_closeFoo", p) }( ) Destructor Foo called used (Mb) gc trigger (Mb) max used (Mb) Ncells 107681 2.9 350000 9.4 350000 9.4 Vcells 74967 0.6 786432 6.0 354231 2.8