[Rcpp-devel] Trouble passing arguments to R functions that have been passed in (maybe)

Anthony Lee awllee at gmail.com
Wed Sep 12 17:54:05 CEST 2012


On 12/09/12 06:56, Christian Gunning wrote:
> On Tue, Sep 11, 2012 at 3:00 AM,
> <rcpp-devel-request at lists.r-forge.r-project.org> wrote:
>> It seems to be the casethat when the memory issue occurs, garbage
>> collection has just been called by R, at least according to gcinfo.In
>> particular, it is called when bar is called and cleans up the arguments
>> that bar is about to use, thus causing a problem.
>>
>> Is there a way to ensure the safety of the arguments that are sent back
>> to R?
> I've gotten in the habit of being very explicit with Rcpp -- limiting
> the use of nested functions, doing one step per line.  I'm don't
> understand the internals enough to understand the exact
> metaprogramming/template details, and I've often seen "odd behavior"
> disappear when I unpack a long, complicated line into component lines
> of code. This is similar to Dirk's comment about limiting use of
> temps.
>
> Also, have you looked at Armadillo for submatrix access?  You can
> easily pull out columns/rows into NumericVectors.  Sometimes I find
> the logical separation between pure C++ (arma) and chameleon SEXP/Rcpp
> conceptually helpful.
>
> Curious to hear your results,
> Christian
> University of New Mexico
>
So, in my actual application this hasn't caused any major problems as I 
have tried to avoid creating too many temporary vectors, following 
Dirk's suggestion.However, the code seems like it should be able to 
fail, albeit rarely, which is at least slightly worrying.

Getting rid of the matrices and using lists so to avoid temporaries is 
also helpful. See the below code (foo.good), which doesn't seem to fail 
for me.

I also discovered that foo.bad actually fails not when the arguments are 
passed into R but when the return value is passed back to Rcpp (with an 
accompanying garbage collection).

Code:
library(inline)

foo.bad <- cxxfunction(
   signature(N_in = "numeric", n_in = "numeric", bar_in = "function"), 
body='
   BEGIN_RCPP
   int N = as<int>(N_in);
   int n = as<int>(n_in);
   Function bar(bar_in);
   IntegerMatrix A(N,n);
   A(_,0) = seq_len(N);

   IntegerVector temp_out(N);
   IntegerVector temp_in(N);
   for (int i = 1; i < n; i++) {
//    std::cerr << "entering bar" << std::endl;
     A(_,i) = as<IntegerVector>(bar(A(_,i-1),N,true));
//    std::cerr << "left bar" << std::endl;
   }
   return wrap(A);
   END_RCPP
   ', plugin = "Rcpp" )

foo.good <- cxxfunction(
   signature(N_in = "numeric", n_in = "numeric", bar_in = "function"), 
body='
   BEGIN_RCPP
   int N = as<int>(N_in);
   int n = as<int>(n_in);
   Function bar(bar_in);
   List A(n);
   A[0] = seq_len(N);

   IntegerVector temp_out(N);
   IntegerVector temp_in(N);
   for (int i = 1; i < n; i++) {
//  std::cerr << "entering bar" << std::endl;
   A[i] = bar(A[i-1],N,true);
//  std::cerr << "left bar" << std::endl;
   }
   return wrap(A);
   END_RCPP
   ', plugin = "Rcpp" )

bar <- function(vs,M,cond) {
#   print("entered bar")
   if (cond) {
     ret <- (vs + 1) %% M
   } else {
     ret <- (vs - 1) %% M
   }
#   print(mean(ret))
#   print("leaving bar")
   return(ret)
}

runCode <- function(f,K) {
   for (k in 1:K) {
     for (i in 1:5) {
       for (j in 1:10) {
#         print(paste(i,j,sep=" "));
         B <- f(i*100,j*100,bar);
       }
     }
   }
}

# gcinfo(TRUE)

print("running foo.good:")
runCode(foo.good,5)
print("running foo.bad:")
runCode(foo.bad,5)




More information about the Rcpp-devel mailing list