동일한 벡터에 대한 두 개의 참조가 벡터의 각 요소에 대해 서로 다른 메모리 주소를 반환하는 이유는 무엇입니까?


9

저는 R을 배우고 있으며 현재이 책을 읽고 있습니다. 개념을 이해하기 위해 다음 테스트를 실행하여 매우 혼란 스러웠으며 명확하게 설명해 주시면 감사하겠습니다. 다음은 터미널에서 R 셸에서 직접 실행 한 테스트입니다 (RStudio 또는 Emacs ESS를 사용하지 않음).

> library(lobstr)
>
> x <- c(1500,2400,8800)
> y <- x
> ### So the following two lines must return the same memory address
> obj_addr(x)
[1] "0xb23bc50"
> obj_addr(y)
[1] "0xb23bc50"
> ### So as I expected, indeed both x and y point to the same memory 
> ### location: 0xb23bc50
>
>
>
> ### Now let's check that each element can be referenced by the same
> ### memory address either by using x or y
> x[1]
[1] 1500
> y[1]
[1] 1500
> obj_addr(x[1])
[1] "0xc194858"
> obj_addr(y[1])
[1] "0xc17db88"
> ### And here is exactly what I don't understand: x and y point 
> ### to the same memory address, so the same must be true for 
> ### x[1] and y[1]. So how come I obtain two different memory
> ### addresses for the same element of the same vector?
>
>
>
> x[2]
[1] 2400
> y[2]
[1] 2400
> obj_addr(x[2])
[1] "0xc15eca0"
> obj_addr(y[2])
[1] "0xc145d30"
> ### Same problem!
>
>
>
> x[3]
[1] 8800
> y[3]
[1] 8800
> obj_addr(x[3])
[1] "0xc10e9b0"
> obj_addr(y[3])
[1] "0xc0f78e8"
> ### Again the same problem: different memory addresses

내 실수가 어디인지,이 문제에서 내가 잘못 이해 한 것이 무엇인지 말해 줄 수 있습니까?


1
나는 R을 모르지만 다른 언어에서는 가치와 참조 유형이 있습니다. 정수가 C ++ 또는 C #에서와 같이 값 유형이면 할당이 새 정수를 작성합니다. 따라서 모든 정수에는 고유 한 주소가 있습니다.
호스텔

1
실제로 obj_addr(x[1])두 번 실행하더라도 새로운 정수마다 자체 주소가 있으므로 다른 결과를 제공해야합니다.
Bas

@Bas 나는 당신이 언급 한 것을 테스트했다. 즉, 연속적으로 obj_addr (x [1])을 실행하고 실제로 그렇게하면 R은 매번 다른 결과 (다른 메모리 주소)를 반환한다. 그러나 왜 그런지 이해하지 못합니다. 왜냐하면 나에게 아무것도 할당하지 않았기 때문에 새 객체를 만들지 않습니다 (물론 R에서 객체를 변경할 수 없으므로 새로운 주소가 있음). 나를 위해 obj_addr (x [1])은 이미 기존 객체를 읽는 중임을 의미합니다.
user17911

답변:


5

모든 R 객체는 C (포인터라고 불림 SEXP) "다중 객체"( struct)입니다. 여기에는 lengthR 객체에 대한 정보 (R이 작동해야하는 참조 수 , 예를 들어 객체를 복사 할시기 등을 알기 위해 필요한 정보 등)와 액세스 할 수있는 R 객체의 실제 데이터가 포함됩니다.

lobstr::obj_addr아마, SEXP가리키는 메모리 주소를 반환합니다 . 메모리의 해당 부분에는 R 개체 의 정보 데이터 가 모두 들어 있습니다 . R 환경 내에서 우리는 각 R 객체에있는 실제 데이터의 (포인터를 가리키는) 메모리에 액세스 할 필요가 없습니다.

Adam이 답변에서 언급 한 것처럼이 함수 는 C 객체에 포함 된 데이터의 n 번째 요소를 새 C 객체로 [ 복사 하고 SEXP포인터를 R로 반환합니다. [호출 될 때마다 새로운 C 객체가 생성되어 R로 반환됩니다.

우리는 R을 통해 객체의 실제 데이터의 각 요소의 메모리 주소에 액세스 할 수 없습니다.하지만 조금만 연주하면 C api를 사용하여 각 주소를 추적 할 수 있습니다.

주소를 얻는 함수 :

ff = inline::cfunction(sig = c(x = "integer"), body = '
             Rprintf("SEXP @ %p\\n", x);

             Rprintf("first element of SEXP actual data @ %p\\n", INTEGER(x));

             for(int i = 0; i < LENGTH(x); i++) 
                 Rprintf("<%d> @ %p\\n", INTEGER(x)[i], INTEGER(x) + i);

             return(R_NilValue);
     ')

그리고 우리의 데이터에 적용 :

x = c(1500L, 2400L, 8800L)  #converted to "integer" for convenience
y = x

lobstr::obj_addr(x)
#[1] "0x1d1c0598"
lobstr::obj_addr(y)
#[1] "0x1d1c0598"

ff(x)
#SEXP @ 0x1d1c0598
#first element of SEXP actual data @ 0x1d1c05c8
#<1500> @ 0x1d1c05c8
#<2400> @ 0x1d1c05cc
#<8800> @ 0x1d1c05d0
#NULL
ff(y)
#SEXP @ 0x1d1c0598
#first element of SEXP actual data @ 0x1d1c05c8
#<1500> @ 0x1d1c05c8
#<2400> @ 0x1d1c05cc
#<8800> @ 0x1d1c05d0
#NULL

객체의 데이터 요소 간의 연속적인 메모리 차이는 int 유형 .

diff(c(strtoi("0x1d1c05c8", 16), 
       strtoi("0x1d1c05cc", 16), 
       strtoi("0x1d1c05d0", 16)))
#[1] 4 4

사용하여 [기능 :

ff(x[1])
#SEXP @ 0x22998358
#first element of SEXP actual data @ 0x22998388
#<1500> @ 0x22998388
#NULL
ff(x[1])
#SEXP @ 0x22998438
#first element of SEXP actual data @ 0x22998468
#<1500> @ 0x22998468
#NULL

이것은 필요 이상의 광범위한 답변 일 수 있으며 실제 기술에 대해서는 단순하지만보다 명확한 "큰"그림을 제공하기를 바랍니다.


대박! R을 완전히 초보자 인 저와 같은 사람들에게 상세하고 명확한 설명을 해주셔서 진심으로 감사드립니다. 또한 R의 유연성과 다른 프로그래밍 언어와의 강력한 상호 작용을 보여주는면에서 매우 인상적입니다. 시간과 도움에 감사드립니다.
user17911

3

이것은 그것을 보는 한 가지 방법입니다. 더 기술적 인 견해가 있다고 확신합니다. R에서 거의 모든 것이 함수라는 것을 기억하십시오. 여기에는 추출 기능이 포함됩니다 [. 다음과 동등한 내용이 있습니다 x[1].

> `[`(x, 1)
[1] 1500

그래서 당신이하고있는 일은 값을 반환하는 함수를 실행하는 것입니다 (check out ?Extract). 그 값은 정수입니다. 당신이 실행하면 obj_addr(x[1]),이 기능을 평가하고 x[1]다음 당신에게주고 obj_addr()당신이 모두 결합하는 배열의 첫 번째 요소의 기능 복귀가 아니라 주소 xy.


내 문제에 대한 귀하의 도움과 관심에 감사드립니다. 실제로 이것은 내가 알지 못한 것입니다. 즉 "추출"로 값을 검색하면 실제로 새로운 객체가 만들어집니다. 내가 말했듯이 나는 정말로 R의 초보자입니다! 시간과 설명 감사합니다.
user17911
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.