파파비의 블로그

C#) 값형식과 레퍼런스형식 2 - 복사에 대한 개념(call by value, call by reference)과 ref 예약어 본문

개발/c#

C#) 값형식과 레퍼런스형식 2 - 복사에 대한 개념(call by value, call by reference)과 ref 예약어

N. Dave 2020. 5. 20. 15:58
반응형

 

값형식과 레퍼런스형식(참조형식)이 존재한다는 것을 우리는 알고 있다.

 

int, short 처럼 메모리에서 스택 부분에 바로 값이 저장되는 형식을 값형식이라고 하며,

평범한 class의 객체나,  string 객체같은 것들은 일차적으로 스택에 주소가 저장되며

그 주소는 힙메모리에 저장된다. 그래서 우리가 레퍼런스 형식의 객체를 호출하면

 

우리는 먼저 스택으로 가서 주소를 확인한 후, 힙 메모리에 가서 정확한 값을 확인한다.

참고로 힙메모리는 GC(가비지 컬렉터)에 의해 컨트롤 되어서,

종종 GC가 발동할 때면 비용이 크게 들어 잠깐씩 멈출 수 있다.

 

이제 우리가 이런 것들을 메소드에 넘길 때, 값들은 어떻게 적용되는 걸까?

전달된 값을 그대로 사용할까 아니면 따로 복사해서 사용하는 것일까?

 

c#에서는,

기본적으로 메소드에 인자들을 넣으면,

새로운 메모리에, 해당 인자의 스택 값을 복사하여 넣게 된다.

이것을 Call by Value, 값에 의한 호출이라고 한다.

기본적으로 c#은 call by value 형식이다.

 

call by value에 의해

값형식은 그대로 새로운 값이 새로운 메모리에 할당되는 것이며,

참조형식의 경우에는 주소가 다른 메모리에 힙메모리를 가르키는 주소가 복사되는 것이다.

 

여기서 그래서 주의해야할 점은, 내부적으로 메소드에서 어떤 조작을 하더라도

값형식은 기존의 값이 변형되지 않는다. 

 

예를 들면 

아래처럼 코드를 실행해보자

 

int a = 3;

add(a); // add는 인자값에 3을 더 한다.

Console.Writeline(a); 

 

콘솔에는 어떤 값이 나올까? 

6이 아니라 3이 나온다. 새로운 메모리에 3과 같은 값이 저장됐고, 새로운 메모리에 저장된 값이 6이 되었다.

그러나 그 6의 값은 add함수가 끝나면서 정리됐을 것이다.

그리고 콘솔에는 그대로 a의 값인 3이 나온다.

 

반대로 

어떤 객체의 값을 넣는다면 어떻게 될까?

메소드의 복사형식은 스택값을 복사해서 새로운 메모리에 할당하는 것인데,

새로운 메모리에 할당된 값은 주소값이고, 결국 같은 힙메모리에 있는 값을 가르키게 된다.

 

그래서 add함수에 int가 아니라 참조형식의 값을 넣으면 실제로 값이 변형된다.

그래서 참조형식은 메소드에서 조작을 한뒤에 다시 값을 불러와보면 변형된 것을 알 수 있다.

 

call by value의 개념을 익혔다면

이제 call by reference에 대해 알아보자

c#은 메소드에 인자를 전달할 때, call by reference를 실행하는 방법으로 ref라는 키워드를 제공한다.

(out이라는 키워드도 있다. 그것은 다음 기회에 다루도록하겠다)

 

ref의 개념에 대해서 알아보자

ref 예약어를 사용하면 메소드에서 복사방식이 기존의 '새로운 메모리에 스택값을 복사' 하는 방식이 아닌,

'해당 인자의 스택값'을 가르키게 된다. (call by reference방식)

 

즉, 넣는 인자값과 동일한 스택메모리를 가르키게 되어서,

ref를 사용한 메소드는 int처럼 값형식을 넣어도 메소드가 끝난 뒤에는 값이 변형될 수 있다.

 

참조형식은 분명 그냥 복사와 ref를 활용한 복사는 다르지만, 결과에 크게 다르진 않다.

다른점은 동일한 주소를 각각 다른 스택 메모리를 통해 접근하느냐, 아니면 같은 메모리를 통해 접근하느냐이다.

 

ref를 사용하는 방식은 간단하다.

1. 메소드를 작성할 때 ref를 사용하는 것이다. 파라미터부분에 타입앞에 ref를 적어주면 된다. 

2. 그리고 메소드를 호출할 때, 인자에 ref를 넣어주기만 하면 된다.

 

ref 같은 경우, 한번에 2개의 return값을 주고 싶을 때 쓰기도 한다.

정식으로 return을 통해 하나의 output을 내고, ref를 통해 변경된 값을 또다른 return으로 인식하기도 한다.

 

 

반응형
Comments