Home 참조 형식에 ref는 무슨 의미일까
Post
Cancel

참조 형식에 ref는 무슨 의미일까

내용에 오류가 있을 수 있습니다.
틀린 부분은 댓글로 남겨주세요!
캡쳐 이미지는 모두 설명을 위해 간단하게 만든 것입니다. (스택에 쌓이는 순서 고려하지 않았습니다.)

1. 값 형식, 참조 형식

C++을 하다가 C#을 하면서 가장 난해하고 이해하기 어려웠던 부분이 값 형식과 참조 형식이었다.
C++에서의 포인터나 레퍼런스처럼 명확한 느낌이 아니였기에 더 그렇게 느낀 듯….

그래서 결국 값 형식, 참조 형식은 무엇이냐?

간단하게 정리하면,
값 형식은 스택에 값의 데이터가 들어가있고
참조 형식에는 스택에 힙의 메모리 주소가 들어가 있다고 보면 된다.

대부분 컴공과 출신이라면 한번쯤 해보았을
call by value / call by reference의 국민 테스트 SWAP 기능을 만들어보자

값 형식 테스트

스택에 데이터 값이 들어가 있기 때문에 당연히 n은 1이 나온다.

파라미터에 ref로 보내지 않았기에 call by value인 값 복사가 이루어진다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void Main(string[] args)
{
	int n = 1;

	Change(n);
	
    // 결과 => n: 1
	Console.WriteLine($"n: {n}");
}

static void Change(int n)
{
	n = 100;
}

참조 형식 테스트

스택에 힙의 메모리 주소가 들어가 있기 때문에 t.n 은 1이 아닌 100으로 변경되어 출력된다.
파라미터에 ref로 보내지 않았기에 call by value인 값 복사가 이루어진다.

아래 이미지와 같이 지역 변수 t 와 매개 변수 t1 모두 힙의 주소를 가지고 있기 때문

cs_01

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Test
{
	public int n;

	public Test()
	{
		n = 1;
	}
}

static void Main(string[] args)
{
	Test t = new Test();

	Change(t);
    
	// 결과 => t.n = 100
	Console.WriteLine($"t.n: {t.n}");
}

static void Change(Test t1)
{
	t1.n = 100;
}

2. 참조 형식에 ref를 써야하는 이유

ref를 안쓴다면…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Test
{
	public int n;

	public Test()
	{
            n = 1;
	}
}

static void Main(string[] args)
{
	int n1 = 1;
	int n2 = 2;

	SWAP(n1, n2);

	Console.WriteLine($"n1: {n1} / n2: {n2}");

	Test t1 = new Test();
	t1.n = 1;
	Test t2 = new Test();
	t2.n = 2;

	SWAP(t1, t2);

	Console.WriteLine($"t1.n: {t1.n} / t2.n: {t2.n}");

}

static void SWAP(int pn1, int pn2)
{
	int pn3 = pn1;
	pn1 = pn2;
	pn2 = pn3;
}

static void SWAP(Test t1, Test t2)
{
	Test t3 = new Test();
	t3.n = t1.n;

	t1 = t2;
	t2 = t3;
}

결과는 아래와 같다.

cs_02

값 형식은 개발자라면 당연히 SWAP 되지 않을 걸 알 수 있다.

왜 그런지 궁금하다면,
call by value / call by reference 를 검색해보자!!

여기서 필자는
“참조 형식은 메모리 주소를 가지고 있는데도 왜 SWAP이 되지 않는가?” 의문이 들었다.

SWAP 되지 않는 이유

생각해보면 간단하다.
참조 형식은 결국 스택에 데이터가 저장된 힙 메모리의 주소값을 저장하고 있는 것이다.

그림으로 설명하면
SWAP 메소드를 들어오게 되면 매개 변수가 스택 메모리에 새로 할당된다.

값 복사가 이루어지기 때문에 t1 과 t2의 스택 데이터 값이 pt1 과 pt2에 복사된다.

cs_03

여기서

1
2
3
4
5
6
7
8
static void SWAP(Test t1, Test t2)
{
	Test t3 = new Test();
	t3.n = t1.n;

	t1 = t2;
	t2 = t3;
}

를 통하게 되면,
그저 각 변수의 스택 데이터 값만 바뀌게 되는 것이다.

참조 형식은 그저 스택에 HEAP에 있는 데이터 주소 값만 가지고 있는 것 뿐이다.

이어서 SWAP 메소드를 빠져나가게 되면,
스택 데이터 값만 바뀐 상황이고, HEAP 메모리에 있는 AT, BT 데이터는 변동이 없으므로 SWAP 되지 않은 값이 노출되는 것이다.

SWAP 메소드를 아래와 같이 바꿔본다면, 바로 이해할 수 있을 것이다.
-> 아래가 코드가 SWAP 되는 이유는
-> 당연하게도 매개 변수가 가리키는 힙 데이터에 접근해서 데이터를 바꿔주기 때문이다.

1
2
3
4
5
6
7
8
static void SWAP(Test t1, Test t2)
{
	Test t3 = new Test();
	t3.n = t1.n;

	t1.n = t2.n;
	t2.n = t3.n;
}

ref를 쓴다면…

1
2
3
4
5
6
7
8
static void SWAP(ref Test t1,ref Test t2)
{
	Test t3 = new Test();
	t3.n = t1.n;

	t1 = t2;
	t2 = t3;
}

call by reference로 인해 정상적으로 값이 변경됨을 알 수 있다.

3. 정리

복잡하게 생각하지 말자!!

  • 값 형식 / 참조 형식은 그저 스택에 어떤 데이터를 넣냐의 차이이다.
    • 값 형식: 데이터 값
    • 참조 형식: HEAP 메모리에 있는 데이터의 주소 값
This post is licensed under CC BY 4.0 by the author.