새소식

인기 검색어

게임 개발/언리얼 강의 (클라-서버)

[언리얼 MMORPG pt1] 포인터 vs 참조

  • -

포인터 vs 참조

  • -성능: 똑같음
  • 편의성: 참조 승!

1. 편의성 관련

편의성이 좋다는게 꼭 장점만은 아니다

포인터는 주소를 넘기니 확실하게 원본을 넘긴다는 힌트를 줄 수 있는데,

참조는 자연스럽게 모르고 지나칠 수도 있음

StatInfo info;

// 포인터
PrintInfo(&info);

// 참조
PrintInfo(info);

만약 신입이 와서 info.hp = 10000; 이런식으로 조져버릴수도 있다. -> const 사용해서 방지

 

const 사용

별(*)기준, 앞에다 붙이는것과 뒤에 붙이는게 다름

 

  • 별 뒤에 붙인다면?
    • StatInfo* const info
    • info = &globalInfo; 가 막힘
    • info라는 바구니의 내용물[주소]을 바꾸지 못하게
    • info 주소값을 갖는 바구니 -> 주소값이 고정이다.
  • 별 이전에 붙인다면?
    • const StatInfo* info => 일반적으로 사용하는 방법
    • StatInfo const* info
    • info->hp = 10000; 가 막힘
    • info가 가리키고 있는 바구니의 내용물을 바꿀 수 없음

2. 초기화 여부

참조 타입은 바구니의 2번째 이름(별칭)

-> 참조하는 대상이 없으면 안됨!

반면 포인터는 그냥 어떤 주소라는 의미

-> 대상이 실존하지 않을 수도 있음

// 포인터
StatInfo* pointer; // 문제없음
pointer = &info;
PrintInfo(pointer);

StatInfo* pointer = &info; // 이렇게 줄여도 됨.
PrintInfo(pointer);

// 참조
StatInfo& reference; // -> 에러발생
reference = info;
PrintInfo(referecne);

StatInfo& reference = info; // 대상이 있어야 함
PrintInfo(reference);

 

포인터에서 '없다'는 의미?

NULL

StatInfo* pointer = nullptr; // -> 더욱 권장하는 방식
StatInfo* pointer = NULL;

실제 게임을 만들때 게임이 뻗어버리는 이유의 80% 이상은 null crash!!

널 포인터에 접근하려 하면 뻗어버림

 

참조타입은 이런 nullptr라는게 없음.

 

그럼 무조건 없는게 좋은건가?

-> 널 있는게 좋을때도 있음

-> 만약 특정 조건을 만족하는 몬스터를 찾는 함수 FindMonster()함수가 있다고 해 보자.

// 특정 조건을 만족하는 몬스터를 찾는 함수
StatInfo* FindMonster()
{
	// Heap 영역에서 뭔가를 찾아봄
    // 찾았다!!
    // return monster~~;
    
    // 만약 못찾으면?
    retun nullptr
}

참조에서는 없다라는 것을 표시할 방법이 없음.

 

그래서 포인터를 사용하기 전에는 항상 긴장해라

포인터값 받아와서 사용 전에는 항상 널 체크를 해라.

if (info == nullptr)
	return;

 

3. 그래서 결론은?  포인터 vs 참조 뭘 써야 하는데?

사실 Team by Team 이다.

정해진 답은 없다.

ex) 구글에서 만든 오픈소스를 보면 거의 무조건 포인터 사용

ex) 언리얼 엔진에선 reference도 애용

 

Rookiss 선호 스타일)

  • '없다'는 경우도 고려해야 한다면 포인터 사용
  • 바뀌지 않고 읽는 용도(readonly)만 사용하면 const ref&
  • 그 외 일반적으로는 ref 선호 (명시적으로 호출할때 OUT을 붙인다) 
    • const를 붙여놓은 경우면 상관없는데 아니라면
    • 앞에 OUT을 붙여줌 (C#에서는 있는 기능, C++에서는 선언해서 사용, 언리얼등에서 많이 사용됨)
  • 단, 다른 사람이 pointer 를 만들어놓은걸 이어서 만든다면, 계속 pointer 사용. (즉, 섞어서 쓰지는 않음)
  • 어찌됐든 팀에서 사용하는 스타일을 잘 따라라
// 아무 define도 하지 않음. 오직 코드상의 힌트로 적기 위한 용도
#define OUT

void ChangeInfo(OUT StatInfo& info)
{
	info.hp = 1000;
{

4. 보너스

포인터로 사용하던걸 참조로 넘겨주려면?

참조로 사용하던걸 포인터로 넘겨주려면?

#include <iostream>
using namespace std;


struct StatInfo
{
	int hp;
	int attack;
	int defence;
};

void CreateMonster(StatInfo& stat)
{
	stat.hp = 100;
	stat.attack = 8;
	stat.defence = 2;
}

void PrintInfoByRef(StatInfo& stat)
{
	cout << "HP: " << stat.hp << endl;
	cout << "Attack: " << stat.attack << endl;
	cout << "Defence: " << stat.defence << endl;
}

void PrintInfoByptr(StatInfo* stat)
{
	cout << "HP: " << stat->hp << endl;
	cout << "Attack: " << stat->attack << endl;
	cout << "Defence: " << stat->defence << endl;
}

int main()
{
	StatInfo stat;
	CreateMonster(stat);

	StatInfo* pointer = &stat; // 포인터
	StatInfo& reference = stat; // 참조

	// 포인터로 사용하던걸 참조로 넘겨주려면?
	PrintInfoByRef(*pointer);

	// 참조로 사용하던걸 포인터로 넘겨주려면?
	PrintInfoByptr(&reference);

	return 0;
}

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.