Web pages of Lars Relund Nielsen

Testing external pointers with finalization in R using C++

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

Leave a Reply