ecsimsw

Reference type / Value type 본문

Reference type / Value type

JinHwan Kim 2019. 1. 14. 07:15

Reference type / Value type

  • Memory structure
    - 먼저 메모리가 어떻게 구조되었는지 공부하였다.
    - 메모리는 OS에서 프로그램의 실행을 위해 공간을 할당받는 공간이다. 대표적인 메모리는 code/ data/ stack/ heap 영역이있고 아래 그림과 같은 구조를 갖는다.
    - 'code 영역'는 실행한 프로그램의 코드, 'data 영역'은 global variable/ static variable, 'heap 영역'은 사용자의 동적 할당 데이터, 'stack 영역'은 지역 변수나 매개 변수를 저장한다.

    - 힙 영역은 생성자/ 소멸자 또는 garbage collector에 의해 데이터가 저장/ 소멸되고, 스택 영역은 함수의 스코프 안에서 저장/ 소멸된다.
    메모리 구조나 각 영역의 역할은 OS 게시판에서 포스팅하였다.
  • Value type
    - Value type에는 struct와 enum이 있다.
    > 값 형식하면 흔히 떠올릴 단순 형식은 모두 System 네임스페이스에 미리 정의된 구조체 형식의 별칭이다.
    ( ex> System.int32 -> int )
    - 이 value type의 데이터는 선언 시 해당 함수의 스택 프레임에 포함되고, 스코프 밖으로 벗어나면 소멸되어 모든 데이터를 잃게된다.
    - 각 변수에 데이터 자체의 사본이 들어 있으며 한 변수의 작업이 다른 변수에 영향을 미칠 수 없다.
  • Reference type
    - Reference type으로 데이터를 선언할 때는 class, interface, delegate의 키워드가 사용된다.
    > dynamic, object와 같은 기본 참조 형식도 사용되는데 따로 포스팅할 것이다.

    Reference type / Value type

    - reference type variable은 데이터에 대한 참조가 저장되는 객체이다. 아래 그림과 같이 동적으로 heap에 할당된 data의 주소 값을 저장한 변수를 스택에 갖는 것이다.
  • Example _ swap
    "wrong swap" static void Main(string[] args) { int a = 10; int b = 12; Swap(a, b); Console.WriteLine("a = {0}, b= {1}", a, b); } private static void Swap(int x, int y) { int temp = x; x = y; y = temp; }
    - 위의 swap 함수는 a와 b의 값을 swap하고자 했으나 결과는 변함 없이 a=10, b=12이다. 값 형식인 a와 b를 main에서 선언하면 main 함수의 스택 프레임에 a=10, b=12가 저장되고, Swap 함수가 인자로 a, b를 호출했을 때, 새로운 swap 함수의 스택 프레임에 parameter x=10, y=12가 저장된다.
    - 이후 Swap 함수가 진행되면서 해당 스텍 프레임에는 x=12, y=10으로 x,y의 값이 변경되나 swap 함수의 종료와 함께 이 데이터들은 소멸되고 다시 main 스택 프레임으로 돌아와 a=10, b=12만이 남아 출력되는 것이다.
    - 해당 코드가 swap을 수행하려면 swap의 parameter x,y가 10, 12의 값을 대입받는 것이 아닌 a, b를 직접 다룰 수 있는 방법을 생각해야하고, 주소를 참조하는 것이 해결 방안이 된다.
    "swap" static void Main(string[] args) { int a = 10; int b = 12; Swap(ref a, ref b); Console.WriteLine("a = {0}, b= {1}", a, b); } private static void Swap(ref int x, ref int y) { int temp = x; x = y; y = temp; }
  • Example _ Data copy
    - 다음 코드에서 원하는 것은 Anderson이라는 데이터를 Neo라는 데이터에 복사하고 Neo에서 해당 데이터의 name 변수만 수정하는 것이다.
    "Shallow copy" class Program { static void Main(string[] args) { Person Anderson = new Person("Anderson"); Person Neo = new Person(); Neo = Anderson; Neo.name = "Neo"; Console.WriteLine(Anderson.name); } } class Person { public string name; public Person() { } public Person(string name){ this.name = name; } }
    - Neo라는 객체는 Person으로 인스턴스되고 Neo = Anderson 으로 copy를 시도한다. 그것으로 Neo.name="Neo"로 해당 데이터의 name 변수만 수정하고 싶었을 것이다.
    - 하지만 Anderson.name의 원래 값을 출력하면 그 값은 Anderson이 아니라 Neo가 된다. 이것은 Neo 객체가 copy한 것은 Anderson 데이터의 객체 내부의 데이터가 아니라 그 주소만을 복사하였기 때문이다. 따라서 Neo.name이 가리키고 있는 것은 Neo 자체의 데이터가 아니라 Anderson.name을 가리키고 있는 것이다.
    - 이처럼 객체를 복사하고자 할 때 그 데이터가 아닌 주소값만을 copy해서 가져오는 것을 Shallow Copy라고 한다. ref 변수와 유사하게 변수가 자체의 새로운 메모리를 갖는 것이 아닌 기존 메모리의 별명만으로 사용되는 것이다.
    - Neo 변수에 자체의 메모리를 생성하고 Anderson 데이터를 복사하고자 하면 다음처럼 코드를 작성해야한다.
    "Deep copy" class Program { static void Main(string[] args) { Person Anderson = new Person("Anderson"); Person Neo = new Person(Anderson); Neo.name = "Neo"; Console.WriteLine(Anderson.name); } } class Person { public string name; public Person() { } public Person(string name){ this.name = name; } public Person(Person previousPerson) { this.name = previousPerson.name; } }
    - 위처럼 Neo의 생성자의 argument로 Person 타입의 객체를 받고 this 키워드를 사용하여 값을 복사하는 것처럼 복사를 위한 메소드를 새로 만드는 것으로 위 상황을 해결할 수 있고, 이런 복사를 Deep Copy라고한다.

'Language > C++, C#' 카테고리의 다른 글

C# / Iterators/ IEnumerator, IEnumerable / yield  (0) 2019.03.01
C# / Is와 As  (0) 2019.01.18
OOP / Up Casting / Down Casting  (0) 2019.01.18
OOP / Class vs Struct / Memory aspects  (0) 2019.01.16
OOP / Encapsulation  (0) 2019.01.15
Comments