r - Within C++ functions, how are Rcpp objects passed to other functions (by reference or by copy)? -
i've finished writing new version of abcoptim package using rcpp. around 30x speed ups, i'm happy new version's performance (vs old version), i'm still having concerns on if have space improve performance without modifying code.
within main function of abcoptim (written in c++) i'm passing around rcpp::list object containing "bees positions" (numericmatrix) , numericvectors important information algorithm itself. question is, when i'm passing rcpp::list object around other functions, e.g.
#include <rcpp.h> using namespace rcpp; list abcinit([some input]){[some code here]}; void abcfun2(list x){[some code here]}; void abcfun3(list x){[some code here]}; list abcmain([some input]) { list x = abcinit([some input]); while ([some statement]) { abcfun2(x); abcfun3(x); } ... return list::create(x["results"]); }
what rcpp within while loop? x object passed reference or deep copy functions abcfun2
, abcfun3
? i've seen usage of 'const list&x', tells me can pass rcpp objects using pointers, thing need list variable (and no constant), there anyway improve this? i'm afraid iterative copy of x list can slowing down code.
ps: i'm still new c++, furthermore i'm using rcpp learn c++.
there no deep copy in rcpp unless ask clone
. when pass value, making new list
object uses same underlying r object.
so different small between pass value , pass reference.
however, when pass value, have pay price protecting underlying object 1 more time. might incur cost rcpp relies on recursive not efficient r_preserveobject
.
my guideline pass reference whenever possible don't pay protecting price. if know abcfun2
won't change object, i'd advise passing reference const : abcfun2( const list& )
. if going make changes list
, i'd recommend using abcfun2( list& )
.
consider code:
#include <rcpp.h> using namespace rcpp ; #define dbg(msg,x) rprintf("%20s sexp=<%p>. list=%p\n", msg, (sexp)x, &x ) ; void fun_copy( list x, const char* idx ){ x[idx] = "foo" ; dbg( "in fun_copy: ", x) ; } void fun_ref( list& x, const char* idx ){ x[idx] = "bar" ; dbg( "in fun_ref: ", x) ; } // [[rcpp::export]] void test_copy(){ // create list of 3 components list data = list::create( _["a"] = 1, _["b"] = 2 ) ; dbg( "initial: ", data) ; fun_copy( data, "a") ; dbg( "\nafter fun_copy (1): ", data) ; // alter 1st component of ths list, passed value fun_copy( data, "d") ; dbg( "\nafter fun_copy (2): ", data) ; } // [[rcpp::export]] void test_ref(){ // create list of 3 components list data = list::create( _["a"] = 1, _["b"] = 2 ) ; dbg( "initial: ", data) ; fun_ref( data, "a") ; dbg( "\nafter fun_ref (1): ", data) ; // alter 1st component of ths list, passed value fun_ref( data, "d") ; dbg( "\nafter fun_ref (2): ", data) ; }
all i'm doing pass list function, update , print information pointer underlying r object , pointer list object ( this
) .
here results of happens when call test_copy
, test_ref
:
> test_copy() initial: sexp=<0x7ff97c26c278>. list=0x7fff5b909fd0 in fun_copy: sexp=<0x7ff97c26c278>. list=0x7fff5b909f30 after fun_copy (1): sexp=<0x7ff97c26c278>. list=0x7fff5b909fd0 $a [1] "foo" $b [1] 2 in fun_copy: sexp=<0x7ff97b2b3ed8>. list=0x7fff5b909f20 after fun_copy (2): sexp=<0x7ff97c26c278>. list=0x7fff5b909fd0 $a [1] "foo" $b [1] 2
we start existing list associated r object.
initial: sexp=<0x7fda4926d278>. list=0x7fff5bb5efd0
we pass value fun_copy
new list
using same underlying r object:
in fun_copy: sexp=<0x7fda4926d278>. list=0x7fff5bb5ef30
we exit of fun_copy
. same underlying r object again, , our original list
:
after fun_copy (1): sexp=<0x7fda4926d278>. list=0x7fff5bb5efd0
now call again fun_copy
time updating component not on list: x["d"]="foo"
.
in fun_copy: sexp=<0x7fda48989120>. list=0x7fff5bb5ef20
list
had no choice create new underlying r object, object underlying local list
. therefore when out of get_copy
, our original list
original underlying sexp
.
after fun_copy (2): sexp=<0x7fda4926d278>. list=0x7fff5bb5efd0
the key thing here first time "a"
on list, updated data directly. because local object fun_copy
, outer object test_copy
share same underlying r object, modifications inside fun_copy
propagated.
the second time, fun_copy
grows local list
object, associating brand new sexp
not propagate outer function.
now consider happens when pass reference :
> test_ref() initial: sexp=<0x7ff97c0e0f80>. list=0x7fff5b909fd0 in fun_ref: sexp=<0x7ff97c0e0f80>. list=0x7fff5b909fd0 after fun_ref(1): sexp=<0x7ff97c0e0f80>. list=0x7fff5b909fd0 $a [1] "bar" $b [1] 2 in fun_ref: sexp=<0x7ff97b5254c8>. list=0x7fff5b909fd0 after fun_ref(2): sexp=<0x7ff97b5254c8>. list=0x7fff5b909fd0 $a [1] "bar" $b [1] 2 $d [1] "bar"
there 1 list
object 0x7fff5b909fd0
. when have new sexp
in second call, correctly gets propagated outer level.
to me, behavior when passing references easier reason with.
Comments
Post a Comment