[Rcpp-devel] What is the best practice to expose a C structure from 3rd party library into R?

Wush Wu wush978 at gmail.com
Mon Jul 22 10:12:54 CEST 2013


Hi all,

I wrote a wrapper of hiredis, which is a minimalistic C client for the
Redis database. Its name is `Rhiredis` and is much faster than rredis, an
existed redis client of R. Please see http://rpubs.com/wush978/rhiredis for
details.

Thanks for the Rcpp, it is much easier to wrap a C library into R and
extend the features of R.

However, I still want to know if there is a better approach. I tried three
approaches. Here is my opinions.

# Preliminary

Given a 3rd party C library, it usually provides a C structure and
functions of memory management. For example:

```c
struct A {
    int flag;
    // ...
};

A* initA();
void freeA(A* a);
```

The structure `A` need to be stored into a R object and pass to another
function.
Also, the user might need to access `A.flag`. For simplicity, there is only
one field in this example. However, there might be a number of fields in
practice.

# XPtr

Thanks for the user guide of Rcpp modules , this is the first approach I
tried.

We could expose `A` into R as follow:

```cpp
Rcpp::XPtr<A, freeA> a(initA());
```

However, we should write helper function to accessing `A.flag` for every
fields.

# RCPP_MODULE

The guids of Rcpp modules also provides another approach:

```cpp
RCPP_EXPOSED_CLASS(A)

RCPP_MODULE(A) {
  class_<A>("A")
  .field("flag", &A::flag)
  ;
}

//'@export
//[[Rcpp::export]]
SEXP init() {
  BEGIN_RCPP
  return wrap(*initA());
  END_RCPP
}
```

This will produce a S4 class named `A` in R which stores C structure `A`.

However, it also produces memory leak because no `freeA` is called.

Adding `.finalizer(freeA)` in `RCPP_MODULE` will cause an error of freeing
memory twice.

# Embed `A` into C++ class and expose the class with RCPP_MODULE

This approach is implemented in `Rhiredis`.

Finally, I still need to write helper function to expose the field of `A`.
But the user could access these flag in R with operator `$`.

Note that I still need a function to extract the pointer of `A` from
exposed S4 object:

```cpp
template<class T>
T* extract_ptr(SEXP s) {
 Rcpp::S4 s4(s);
Rcpp::Environment env(s4);
Rcpp::XPtr<T> xptr(env.get(".pointer"));
 return static_cast<T*>(R_ExternalPtrAddr(xptr));
}
```

Please give me some suggestion if you know a better or a different approach.

Thanks.

Wush
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20130722/6145122c/attachment-0001.html>


More information about the Rcpp-devel mailing list