6

In the following code, object of type foo is created with a call to foo_new() and an external-pointer to the object is returned to R. Subsequent computations are performed by passing ptr_foo. The object is eventually freed with an explicit call to foo_free(foo *X). All computations are performed by libfoo.

Does the fact that ptr_foo was created mean that all other dynamically allocated fields within the foo object are automatically protected? Or, is it possible that fields such as "bar" may be swept away by the garbage collector?

SEXP foo_new (SEXP n) {
    SEXP ptr_foo;
    foo *X = (foo*) foo_new( 1, sizeof(foo) );
    //foo is protected from garbage collection
    assert( X );
    X->bar = (int*) foo_add_bar(INTEGER_VALUE(n));
    //Is bar protected from garbage collection?
    assert(X->bar);
    PROTECT( ptr_foo = R_MakeExternalPtr(X, install("extptr_foo"), R_NilValue) );
    R_RegisterCFinalizerEx( ptr_foo, ptr_foo_finalize, 1 );
    UNPROTECT( 1 );
    return (ptr_foo);
} 

Thanks,

RT

Tommy
  • 39,997
  • 12
  • 90
  • 85
user151410
  • 776
  • 9
  • 22

2 Answers2

3

It looks like your foo object is your own creation (not and SEXP). If so, it has nothing to do with R and is NOT garbage collected and therefore does not need to be/can't be protected. No one will look at it or its fields but you.

The bar object you put in it is also your own creation and not an R object (an SEXP) I assume. If it IS an SEXP or points to data within an SEXP then that data needs to be protected. A safer/easier way would then be to make a copy of the data in the SEXP.

When the ptr_foo object is no longer used by R and garbage collected, your ptr_foo_finalize function will be called to remove your foo object (and the bar part).

Tommy
  • 39,997
  • 12
  • 90
  • 85
  • Thanks Tommy. That is what I was hoping for. As you indicate, all exchange of data between R and libfoo happens by copying SEXPs in and out. All objects allocated by the library are freed by a foo_free() call. – user151410 Jul 21 '11 at 01:49
1

For starters, you are not supposed to use calloc() or malloc() for R objects, the "Writing R Extensions" manual is pretty clear on that.

Second, each allocation would get its own PROTECT all.

Third, external pointer objects are R representations of something created elsewhere (for a canonical example , see the RODBC package and its implementation of DB interface). I don't think you're supposed to create external pointer objects from within.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
  • Thanks Dirk, I edited my original code. I used `calloc()` just to keep the example simple. Creation, destruction and computations involving `foo` and `bar` are performed by calls to functions in `libfoo`. Thanks for the pointer to RODBC package. – user151410 Jul 20 '11 at 12:45