2011-01-26 3 views
4

ValueType을 Object로 복싱하는 것과 관련된 몇 가지 최근 질문, 특히 특정 인스턴스에서 발생했는지 여부가있었습니다.복싱 비교 ValueType; 차이점이 뭐야?

"복싱"ValueType (참조 된 개체로 처리)과 단순히 참조로 액세스하는 것 (예 : ref 또는 out 키워드 사용)의 차이점은 무엇인지 몰랐습니다. 전달은 그냥 "포인터"입니다)? 두 경우 모두 그 값이 가리킬 수있는 곳입니다 (Object의 경우 힙, 로컬 범위의 ValueType은 정확히 ...).

내가 C++에 대해 알고있는 것으로부터 추측해야만한다면 다음과 같이 작동한다고 말할 수 있습니다. 참조로 액세스되는 ValueType (매개 변수 키워드를 통해 가정 해 봅시다)은 범위가 지정된 호출 스택의 레벨에 남아 있습니다. 스택에서 해당 변수의 버킷에 대한 "바로 가기"포인터가 만들어져 스택의 다음 계층의 일부가됩니다. 값은 이미 메모리 (아마도 CPU 캐시)에 저장되어 있기 때문에 힙에 새로운 것을 인스턴스화 할 필요가 없습니다. 유일한 새로운 것은 자체 ValueType (IntPtr)이며 자체적으로 스택에 저장되는 포인터이므로 AFAIK는 힙에 뭔가를 넣는 것보다 빠를 것입니다.

이게 무슨 일 이니, 아니면 다른 일이 있을까요?

편집 : 더 명확 :

public void TakesAnObject(Object obj) {...} 

public void TakesAnIntValueType(ref int myValue) {...} 

public void AnotherIntParameterMethod(out int myValue) {...} 

... 

//this locally-scoped variable is simply created on the stack. 
int myInt = 5;  

//Performs boxing; an Object is instantiated in the heap that holds the 
//variable value from the stack, and that is passed by ref. 
TakesAnObject(myInt); 

//Apparently does NOT perform boxing, but we're still dealing with a reference. 
//So what's going on? 
TakesAnIntValueType(myInt); 

//Again created on the stack, with the default 0. 
int anotherInt; 

//Again, apparently no boxing, but we're dealing with a reference to anotherInt. 
AnotherIntParameterMethod(anotherInt); 
+0

당신이 이야기하고있는 두 가지 시나리오의 완전한 예제를 줄 수 있다면 도움이 될 것입니다. 지금이 순간 무슨 뜻인지는 분명치 않습니다. –

답변

3

클래스 참조는 자유롭게 복사 할 수 있으며 무기한으로 존재할 수 있습니다. 하나는 힙의 독립형 항목으로 (항상) 저장되는 객체의 식별자로 생각할 수 있습니다. "참조"라는 용어가 지나치게 사용되는 것을 피하기 위해 저는 그것들을 ObjectID로 생각합니다.

루틴이 매개 변수를 참조로 받아 들일 때 해당 참조는 일반 클래스 시스템 외부에있는 특수한 유형의 항목입니다 (ParameterReference라고 부름). 무한히 존재할 수있는 ObjectID와 달리, ParameterReference는 호출 된 함수의 지속 기간 동안 만 존재할 수 있습니다. 또한 독립 객체에 대한 참조를 항상 보유하고있는 ObjectID와 달리 ParameterReference는 스택의 로컬 변수, 클래스 Object 내의 필드, 배열 내의 항목 또는 자체 구조체 내의 필드에 대한 참조를 보유합니다 이 설명 중 하나와 일치합니다. ParameterReference가 로컬 변수를 가리키면 해당 변수는 범위를 벗어나면 존재를 멈 춥니 다. 이 시간이 지나면 ParameterReference를 사용하려고하면 데이터가 손상 될 수 있습니다. 그러나 변수의 범위는 적어도 호출 된 루틴이 종료 될 때까지 확장되므로, ParameterReference가 그 시점에 존재하지 않으므로 ParameterReference가 더 이상 존재하지 않는 변수에 액세스 할 위험이 없습니다.

+0

좋은 답변입니다. Tedd와 거의 비슷하지만 훨씬 더 자세합니다.나는 다른 투표가 당신에게 어느 쪽이 더 낫지 만, 양쪽 모두에게 엄지 손가락을 내리게 할 것이다. – KeithS

+0

KeithS : 고마워. 앞서 언급 한 것처럼 "참조"라는 용어는 혼란 스럽기 때문에 "ObjectID"를 사용하면 더 명확하게 알 수 있습니다. BTW, 난. NET에서 "진짜"참조와 함께 더 많은 일을 할 수있는 가치 - 유형 속성 반환 하나처럼. 에릭 리 퍼트 (Eric Lippert) 외 다수의 불만. 변경할 수있는 구조체에 대한 것 같다 제대로 작동하는 데 어려움에 대한 불만이 있습니다. – supercat

-1

당신이 가까이있어. 값 유형이 박스형 일 경우 GC 힙에있는 객체 구조에 복사됩니다. 객체 구조는 객체에 대한 일반적인 프리앰블을 가지며, 그 뒤에 나오는 비트는 블리트 값 유형 구조입니다. 박스를 열지 않으면이 구조가 스택에 다시 복사됩니다.

+0

값이 클래스의 인스턴스 필드에 unboxed되면 어떻게 될까요?값이 반복기 또는 익명 대리자에서 캡처 된 변수에 unboxed되면 어떻게 될까요? – jason

+0

@ Jason - 모든 경우를 다루고 싶다면 직접 가서 대답하십시오. 그러나이 답변은 일반적인 경우가 아니라 질문자가 운전 중임을 이해하는 경우를 대상으로합니다. 때때로 더 적은 것이 더 많습니다. – codekaizen

+0

내가 (로컬 variabl 전자 질문에 대한 질문의 범위에 대한 참조되는 boxed), 대답은 정확합니다. 그러나, 그것은 완전하지 않습니다. 나는 그 권투가 가치 유형에 대한 것을 알고, 내가 알고 싶었던 것은 참조로 value 유형을 전달하는 것이 boxing/unboxing과 어떻게 다른지를 아는 것이다. – KeithS

1

TakesAnObject(myInt); 은 객체 유형 (참조 유형)으로 수신되었으므로 상자에 들어 있습니다. 대상이 값 유형이면 대신 복사됩니다.

TakesAnIntValueType(ref myInt); 은 myInt와 동일한 메모리 영역을 참조하므로 "둘 다 변경"됩니다. ref가 아닌 경우 값이 대신 복사됩니다.

+0

이것은 내가 생각한 것입니다. 여전히 참조가 있지만 박스형 대신 참조로 전달 된 값 유형의 경우 참조는 스택의 기존 변수에 대한 것입니다. boxed 될 때 새로운 객체가 힙에서 인스턴스화되고 값이 복사 된 다음 함수가 종료 될 때 힙에서 스택으로 다시 복사됩니다. 절약은 객체 생성 및 복사 프로세스에 있습니다. 포인터를 만드는 것은 저렴합니다. – KeithS

관련 문제