[Rcpp-devel] Forcing a shallow versus deep copy

Romain Francois romain at r-enthusiasts.com
Fri Sep 13 14:15:38 CEST 2013


Le 13/09/13 14:00, JJ Allaire a écrit :
>     Is it a big deal that we would cheat on chat reference passing means ?
>
>
> If you want to implement these sort of semantics I think at a _minimum_
> the type should be const & (otherwise it looks like you are going to
> actually modify the matrix in place which would appear to bypass the
> implicit memory barrier of SEXP). Realize that you won't actually bypass
> the memory barrier but it sure looks like you intend to for a reader of
> the code.

arma::mat has the ability to use auxiliary memory. We might want 
something that modifies the underlying memory of the object, e.g.

void double_me( arma::mat& x){
    x += x ;
}

and changes to x be brought back to the R object we pass in.


But I realize this might be a strech and we can definitely only have 
const references. Which is easier to implement anyway and we would not 
need the reference counting stuff I was talking about before.




The arma::mat ctor I'd use enforces memory to be bound to what we pass 
in for the lifetime of the matrix. From the docs;

     mat(aux_mem*, n_rows, n_cols, copy_aux_mem = true, strict = true)

     Create a matrix using data from writeable auxiliary memory. By 
default the matrix allocates its own memory and copies data from the 
auxiliary memory (for safety). However, if copy_aux_mem is set to false, 
the matrix will instead directly use the auxiliary memory (ie. no 
copying). This is faster, but can be dangerous unless you know what 
you're doing!

     The strict variable comes into effect only if copy_aux_mem is set 
to false (ie. the matrix is directly using auxiliary memory). If strict 
is set to true, the matrix will be bound to the auxiliary memory for its 
lifetime; the number of elements in the matrix can't be changed 
(directly or indirectly). If strict is set to false, the matrix will not 
be bound to the auxiliary memory for its lifetime, ie., the size of the 
matrix can be changed. If the requested number of elements is different 
to the size of the auxiliary memory, new memory will be allocated and 
the auxiliary memory will no longer be used.

>              Rcpp::RNGScope __rngScope;
>              arma::mat& m = Rcpp::as<arma::mat& >(mSEXP);
>              test_ref(m);
>
>
> It looks like this behavior changed as of rev 4400 when the full_name()
> method was introduced. I may not understand the mechanism you
> established 100% but to me this generated code looks potentially
> problematic if you are taking a reference to a stack variable establish
> within the as<> method.

This was to support additional calling capabilities for classes handled 
by modules. If we have a module exposed class, we don't want to have to 
pass it by value as we used to have to.

That change allowed me to pass the object by reference, by const 
reference, by pointer or by const pointer.

With module objects, what is really stored is a pointer to the object, 
so from a T* we can get T&, const T&, T* and const T*

> My guess is that you have something more
> sophisticated going on here and there is no memory problem, however I'd
> love to understand things a bit better to be 100% sure there isn't
> something to drill into further.

What we used to do before is to trim out the const and reference out of 
the parameters, so if we had a function like this:


void foo( const arma::mat& x){
    // do stuff
}

we had an implicit as call, but it was not a call to as< const 
arma::mat&>, it was a call to as< arma::mat >, which was creating a 
copy. So we were implementing pass by reference by using pass by value. 
Not good.

-- 
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30



More information about the Rcpp-devel mailing list