Assignment operator and deep copy for calling C functions

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Assignment operator and deep copy for calling C functions

Thorsten R
Hi All,

i have a problem in understanding what the assignment operator '<-'  really is doing.
If i create two numeric arrays in R and copy one into the other with '<-' and
afterwards change one array by calling a C function, both arrays are changed!

The problem I am facing can easily be seen in the following example:
(The following R code and the C function is attached and the C function can be compiled with R CMD SHLIB test.c.)

First include the c function:
    dyn.load("test.so")

Let's start with 2 arrays:
    a  <- rep(0, 5)
    b  <- rep(1, 5)

Now print the memory addresses:
    print(sprintf("a: %s    b: %s", tracemem(a), tracemem(b) ))
    [1] "a: <0x29d34e0>    b: <0x29946e0>"

oky, they are different! Now copy a into b and print again the addresses:
    b <- a
    print(sprintf("a: %s    b: %s", tracemem(a), tracemem(b) ))
    [1] "a: <0x29d34e0>    b: <0x29d34e0>"

Ugh they are the same. If I now call my C function, which writes 0,1,2,3,4 into an array of 5 doubles,
of course 'both' arrays are changed:
    .Call("test", b)
    print( cbind(a,b) )
         a b
    [1,] 0 0
    [2,] 1 1
    [3,] 2 2
    [4,] 3 3
    [5,] 4 4


If i just change one element of b instead of calling the c function, then a full copy of b is made:
    a <- rep(0, 5)
    b <- rep(1, 5)
    print(sprintf("a: %s    b: %s", tracemem(a), tracemem(b) ))
    [1] "a: <0x2994b58>    b: <0x2912ff8>"

    b <- a
    print(sprintf("a: %s    b: %s", tracemem(a), tracemem(b) ))
    [1] "a: <0x2994b58>    b: <0x2994b58>"

    b[1] <- 5
    print(sprintf("a: %s    b: %s", tracemem(a), tracemem(b) ))
    "a: <0x2994b58>    b: <0x29134d8>"

    print( cbind(a,b) )
         a b
    [1,] 0 5
    [2,] 0 0
    [3,] 0 0
    [4,] 0 0
    [5,] 0 0


So what is happening here? What is the 'right' way to ensure a deep copy before using Call?
I am currently using a for loop and copy every single element.

Thanks!


______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

test.c (382 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Assignment operator and deep copy for calling C functions

Martyn Plummer-3
This is discussed in the "Writing R Extensions" manual section 5.9.10:
Named objects and copying.

.Call does not copy its arguments and it is not safe to modify them, as
you have found, since multiple symbols may refer to the same object. If
you are going to modify an argument to .Call you should take a deep
copy with "duplicate" first, and your function should return the
modified copy.

It is probably also worth mentioning Rcpp, which provides a friendlier
interface to R than the C API. In Rcpp you use clone() to force a deep
copy.

Martyn  


On Tue, 2016-04-05 at 15:38 +0000, Thorsten R wrote:

> Hi All,
>
> i have a problem in understanding what the assignment operator '<-
> '  really is doing.
> If i create two numeric arrays in R and copy one into the other with
> '<-' and
> afterwards change one array by calling a C function, both arrays are
> changed!
>
> The problem I am facing can easily be seen in the following example:
> (The following R code and the C function is attached and the C
> function can be compiled with R CMD SHLIB test.c.)
>
> First include the c function:
>     dyn.load("test.so")
>
> Let's start with 2 arrays:
>     a  <- rep(0, 5)
>     b  <- rep(1, 5)
>
> Now print the memory addresses:
>     print(sprintf("a: %s    b: %s", tracemem(a), tracemem(b) ))
>     [1] "a: <0x29d34e0>    b: <0x29946e0>"
>
> oky, they are different! Now copy a into b and print again the
> addresses:
>     b <- a
>     print(sprintf("a: %s    b: %s", tracemem(a), tracemem(b) ))
>     [1] "a: <0x29d34e0>    b: <0x29d34e0>"
>
> Ugh they are the same. If I now call my C function, which writes
> 0,1,2,3,4 into an array of 5 doubles,
> of course 'both' arrays are changed:
>     .Call("test", b)
>     print( cbind(a,b) )
>          a b
>     [1,] 0 0
>     [2,] 1 1
>     [3,] 2 2
>     [4,] 3 3
>     [5,] 4 4
>
>
> If i just change one element of b instead of calling the c function,
> then a full copy of b is made:
>     a <- rep(0, 5)
>     b <- rep(1, 5)
>     print(sprintf("a: %s    b: %s", tracemem(a), tracemem(b) ))
>     [1] "a: <0x2994b58>    b: <0x2912ff8>"
>
>     b <- a
>     print(sprintf("a: %s    b: %s", tracemem(a), tracemem(b) ))
>     [1] "a: <0x2994b58>    b: <0x2994b58>"
>
>     b[1] <- 5
>     print(sprintf("a: %s    b: %s", tracemem(a), tracemem(b) ))
>     "a: <0x2994b58>    b: <0x29134d8>"
>
>     print( cbind(a,b) )
>          a b
>     [1,] 0 5
>     [2,] 0 0
>     [3,] 0 0
>     [4,] 0 0
>     [5,] 0 0
>
>
> So what is happening here? What is the 'right' way to ensure a deep
> copy before using Call?
> I am currently using a for loop and copy every single element.
>
> Thanks!
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel-----------------------------------------------------------------------
This message and its attachments are strictly confidenti...{{dropped:8}}

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel