Thorsten R
2016-Apr-05 15:38 UTC
[Rd] Assignment operator and deep copy for calling C functions
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! -------------- next part -------------- A non-text attachment was scrubbed... Name: test.c Type: text/x-csrc Size: 277 bytes Desc: test.c URL: <https://stat.ethz.ch/pipermail/r-devel/attachments/20160405/12cf70a5/attachment.bin>
Martyn Plummer
2016-Apr-07 08:48 UTC
[Rd] Assignment operator and deep copy for calling C functions
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! > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel-----------------------------------------------------------------------This message and its attachments are strictly confidenti...{{dropped:8}}