[c#] C # 참조와 포인터의 차이점은 무엇입니까?

C # 참조와 포인터의 차이점을 잘 이해하지 못합니다. 둘 다 기억 속의 장소를 가리 킵니다. 그렇죠? 내가 알아낼 수있는 유일한 차이점은 포인터가 똑똑하지 않고 힙에있는 어떤 것도 가리킬 수없고 가비지 수집에서 제외되며 구조체 또는 기본 유형 만 참조 할 수 있다는 것입니다.

내가 묻는 이유 중 하나는 좋은 프로그래머가되기 위해 사람들이 포인터를 잘 이해해야한다는 인식이 있기 때문입니다. 더 높은 수준의 언어를 배우는 많은 사람들은 이것을 놓치고 따라서 이러한 약점을 가지고 있습니다.

포인터에 대해 그렇게 복잡한 것을 이해하지 못합니까? 그것은 기본적으로 기억의 장소에 대한 참조 일 뿐이지 않습니까? 위치를 반환하고 해당 위치의 개체와 직접 상호 작용할 수 있습니까?

중요한 포인트를 놓친 적이 있습니까?



답변

C # 참조는 가비지 수집기에 의해 재배치 될 수 있으며 재배치되지만 일반 포인터는 정적입니다. 이것이 우리 fixed가 배열 요소에 대한 포인터를 획득 할 때 키워드가 이동되는 것을 방지하기 위해 사용하는 이유입니다.

편집 : 개념적으로, 예. 그들은 다소 동일합니다.


답변

포인터와 참조 사이에는 약간의 차이가 있지만 매우 중요한 차이가 있습니다. 포인터는 메모리의 한 위치를 가리키고 참조는 메모리의 개체를 가리 킵니다. 포인터가 가리키는 메모리의 정확성을 보장 할 수 없다는 점에서 포인터는 “타입 안전”이 아닙니다.

예를 들어 다음 코드를 살펴보십시오.

int* p1 = GetAPointer();

이것은 GetAPointer가 int *와 호환되는 형식을 반환해야한다는 점에서 형식 안전입니다. 그러나 * p1이 실제로 int를 가리킬 것이라는 보장은 아직 없습니다. char, double 또는 임의 메모리에 대한 포인터 일 수 있습니다.

그러나 참조는 특정 개체를 가리 킵니다. 객체는 메모리에서 이동할 수 있지만 참조는 무효화 될 수 없습니다 (안전하지 않은 코드를 사용하지 않는 한). 이 점에서 참조는 포인터보다 훨씬 안전합니다.

string str = GetAString();

이 경우 str은 두 가지 상태 중 하나를 갖습니다. 1) 객체를 가리 키지 않으므로 null이거나 2) 유효한 문자열을 가리 킵니다. 그게 다야. CLR은이를 보장합니다. 그것은 포인터를 위해 할 수 없으며 그렇지 않을 것입니다.


답변

참조는 “추상”포인터입니다. 참조로 산술을 할 수없고 그 값으로 저수준 트릭을 할 수 없습니다.


답변

참조와 포인터의 주요 차이점은 포인터가 포인터로 활발하게 사용되는 경우에만 내용이 중요한 비트 모음 인 반면 참조는 비트 집합뿐만 아니라 일부 메타 데이터를 캡슐화한다는 것입니다. 그 존재를 알린 기본 프레임 워크. 포인터가 메모리에있는 일부 개체에 대해 존재하고 해당 개체가 삭제되었지만 포인터가 지워지지 않은 경우 포인터가 가리키는 메모리에 액세스하려고 시도하지 않는 한 또는 포인터가 계속 존재해도 아무런 해를 끼치 지 않습니다. 포인터를 사용하려는 시도가 없으면 그 존재를 신경 쓰지 않습니다. 반대로 .NET 또는 JVM과 같은 참조 기반 프레임 워크에서는 시스템이 항상 존재하는 모든 객체 참조를 식별 할 수 있어야하며 존재하는 모든 객체 참조는 항상null 또는 적절한 유형의 개체를 식별합니다.

각 개체 참조는 실제로 두 종류의 정보를 캡슐화합니다. (1) 식별하는 개체의 필드 내용 및 (2) 동일한 개체에 대한 다른 참조 집합입니다. 시스템이 객체에 존재하는 모든 참조를 신속하게 식별 할 수있는 메커니즘은 없지만 객체에 존재하는 다른 참조 집합이 참조로 캡슐화되는 가장 중요한 것이 될 수 있습니다 (특히 다음과 같은 경우에 해당). 유형의 Object사물은 잠금 토큰과 같은 것으로 사용됩니다.) 시스템은에서 사용하기 위해 각 객체에 대해 몇 비트의 데이터를 유지하지만 객체에 GetHashCode존재하는 참조 집합을 넘어서는 실제 ID가 없습니다. X객체에 대한 유일한 현존 참조를 보유하는 경우X동일한 필드 내용을 가진 새 객체를 참조하면에서 반환 된 비트를 변경하는 것 외에는 식별 가능한 효과가 없으며 GetHashCode()그 효과조차 보장되지 않습니다.


답변

포인터는 메모리 주소 공간의 위치를 ​​가리 킵니다. 참조는 데이터 구조를 가리 킵니다. 데이터 구조는 모두 가비지 수집기 (메모리 공간 압축을 위해)에 의해 항상 (그렇게 자주는 아니고 가끔씩) 이동했습니다. 또한 언급했듯이 참조가없는 데이터 구조는 잠시 후에 가비지 수집됩니다.

또한 포인터는 안전하지 않은 컨텍스트에서만 사용할 수 있습니다.


답변

개발자가 포인터 의 개념 , 즉 간접 을 이해하는 것이 중요하다고 생각합니다 . 그렇다고 반드시 포인터를 사용해야하는 것은 아닙니다. 그것은 이해하는 것도 중요 기준의 개념 로부터 다릅니다 포인터의 개념 , 참조의 구현은 거의 항상 비록 단지 미묘하지만 입니다 포인터.

즉, 참조를 보유하는 변수는 객체에 대한 포인터를 보유하는 포인터 크기의 메모리 블록입니다. 그러나이 변수는 포인터 변수를 사용할 수있는 것과 같은 방식으로 사용할 수 없습니다. C # (및 C 및 C ++, …)에서 포인터는 배열처럼 인덱싱 될 수 있지만 참조는 그렇지 않습니다. C #에서 참조는 가비지 수집기에 의해 추적되지만 포인터는 추적 될 수 없습니다. C ++에서는 포인터를 다시 할당 할 수 있지만 참조는 할당 할 수 없습니다. 구문 적으로나 의미 적으로 포인터와 참조는 상당히 다르지만 기계적으로는 동일합니다.


답변

먼저 sematics에서 “Pointer”를 정의해야한다고 생각합니다. 고정 으로 안전하지 않은 코드에서 만들 수있는 포인터를 의미 합니까? 네이티브 호출 또는 Marshal.AllocHGlobal 에서 얻은 IntPtr 을 의미 합니까? GCHandle 을 의미 합니까? 클래스, 숫자, 구조체 등 모든 것이 본질적으로 동일한 것입니다. 무언가가 저장된 메모리 주소의 표현입니다. 그리고 기록을 위해 그들은 확실히 힙에있을 수 있습니다.

포인터 (위의 모든 버전)는 고정 된 항목입니다. GC는 해당 주소에 무엇이 있는지 알지 못하므로 개체의 메모리 나 수명을 관리 할 수 ​​없습니다. 즉, 가비지 수집 시스템의 모든 이점을 잃게됩니다. 개체 메모리를 수동으로 관리해야하며 누수가 발생할 가능성이 있습니다.

반면에 참조는 GC가 알고있는 “관리 포인터”입니다. 여전히 객체의 주소이지만 이제 GC는 대상의 세부 정보를 알고 있으므로 이동, 압축, 마무리, 폐기 및 관리 환경이 수행하는 기타 모든 멋진 작업을 수행 할 수 있습니다.

실제로 가장 큰 차이점은 사용 방법과 이유입니다. 관리되는 언어의 대부분의 경우 개체 참조를 사용합니다. 포인터는 interop을 수행하는 데 유용하며 매우 빠른 작업이 거의 필요하지 않습니다.

편집 : 실제로 여기 에 관리 코드에서 “포인터”를 사용할 수 있는 좋은 예가 있습니다.이 경우에는 GCHandle이지만 AllocHGlobal을 사용하거나 고정 된 바이트 배열 또는 구조체를 사용하여 똑같은 작업을 수행 할 수 있습니다. 나는 GCHandle이 나에게 더 “.NET”이라고 느끼기 때문에 선호하는 경향이 있습니다.