Call by Value & Call by Reference 비교
자료형 타입 비교
유니티와 C# 프로그래밍에서 사용되는 Value 타입과 Reference 타입은 다음과 같다.
- 기본 자료형(Value type) : int, float, string, long, short, byte, array, Vector, Struct, enum 등
- 참조 자료형(Reference type) = GameObject, Class, Instance 등
Call by Value (값에 의한 호출)
함수가 호출될 때 메모리 공간 안에는 임시 공간이 생성된다. 마찬가지로 함수가 종료되면 임시 공간은 사라진다.
함수 호출 시 전달되는 변수 값을 복사해서 함수의 인자로 전달한다.
복사된 인자는 함수 안에서 사용하는 지역변수이다.
인자 값을 복사하기 때문에 원래 값은 영향을 받지 않아 안전하다.
하지만 데이터를 복사한 탓에 메모리 양이 증가하고 성능 저하 및 과부화의 원인이 된다.
Call by Reference (참조에 의한 호출)
함수가 호출될 때 메모리 공간 안에는 임시 공간이 생성된다. 마찬가지로 함수가 종료되면 임시 공간은 사라진다.
함수 호출 시 인자로 전달되는 변수의 레퍼런스를 전달한다. (해당 변수를 가리킴)
함수 안에서 인자 값이 변경되면, 함수 호출 시에 있던 변수들도 값이 바뀐다. (수정된 값이 동일한 주소에 저장)
ref 키워드를 사용해서 함수 호출에서 인수를 참조로 전달한다.
원본 자체를 사용하고 원본의 주소를 바꾼다.(포인터)
차이점 비교
Parameters | Call By Value | Call By Reference |
정의 | 함수를 호출할 때 변수를 복사하여 값을 전달 | 함수를 호출할 때 변수를 복사하여 값을 전달하지 않고 변수의 주소를 사용 |
인수 | 변수의 복사본 전달 | 변수 원본 자체 전달 |
효과 | 함수 외부의 값을 수정하지 않음 | 함수 외부의 값에도 영향을 줌 |
값의 변경 | 실제 변수의 값 수정할 수 없음 | 실제 변수의 값 수정할 수 있음 |
값의 수정 | 원본 값이 수정되지 않음 | 원본 값이 수정될 수 있음 |
메모리 위치 | 다른 위치에 생성 | 동일한 위치에 생성 |
안전성 | 원본 값이 변경되지 않으므로 안전 | 원본 값이 변경될 수 있으므로 유의 |
void Start()
{
int a = 10;
int b = 20;
Swap(a, b);
print("a : " + a + ", b : " + b);
int a = 10;
int b = 20;
Swap(ref a, ref b);
print("a : " + a + ", b : " + b);
}
// Call by Value
void Swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
// Call by Reference
void Swap(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
Call by Value의 경우 Swap() 메서드가 적용되지 않고 Start() 함수 내 value 변수가 그대로 출력된다.(int a = 10, int b = 20) 하지만 Call by Reference는 Swap()에서 원본 주소가 바뀌므로 값이 바뀌어서 출력된다. (int a = 20, int b = 10)
실제 코드를 사용할 때 내부적으로 Value 타입을 넘기면 데이터 크기에 따라 복제하는 과정에서 성능 저하, 과부화가 걸릴 수 있기 때문에 대부분 Reference타입으로 참조만 넘겨준다. Ref 타입은 데이터와 관련 없이 주소만 넘기기 때문에 속도가 매우 빠르다. 유니티에서 제공하는 상당한 수의 함수, 유틸리티 메서드들은 Call by Reference라고 보면 된다.
string c = "ho"
string d = c;
char[] c = {"h", "0"}
char[] d = c[0]
char[] d = c[1]
string 타입은 문자'열'이기 때문에 내부적으로는 Array(value type)을 가진다. 실제로 string 값을 저장할 때는 char[] 배열을 생성해 index 번호마다 하나씩 추가해서 저장해주는 개념이기 때문에 복제, 즉 Call by Value 형식을 따른다. 그렇기 때문에 배열에서 데이터를 추가하는 것은 성능적으로 그리 좋지 못하다. 따라서 데이터를 추가해야하는 경우 StringBuilder를 사용해 List처럼 하나씩 넣어주는게 좋다.
StringBuilder sb = new StringBuilder()
sb.Append(0);
sb.Append(1);
'게임 프로그래밍 > 유니티 프로젝트' 카테고리의 다른 글
[유니티] 오브젝트 회전(Euler/Quaternion), Vector3의 외적/내적, 삼각함수를 이용한 플레이어 이동 및 총알 발사 (2022.07.14) (0) | 2022.07.19 |
---|---|
[Unity] File 저장과 PlayerPrefs (0) | 2022.07.15 |
[Unity] 유니티 특수 폴더 [Resources]의 역할과 동적 파일 Resources.Load 방법 (0) | 2022.07.08 |
[Unity] 유니티 2D게임 배경 제작 시 Plane과 Quad 차이 비교 (0) | 2022.07.07 |
[유니티/C#] 일반화(Generic)이란? 제네릭 메서드&제네릭 클래스의 선언 방식과 차이 비교, 제네릭 컬렉션 특징 및 활용 사례 (0) | 2022.07.06 |