오븐 노트

[C++] 포인터 vs 참조 본문

Develop/C++

[C++] 포인터 vs 참조

오 븐 2022. 7. 10. 21:05
#include <iostream>
using namespace std;

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

void CreateMonster(StatInfo* info)
{
	info->hp = 100;
	info->attack = 8;
	info->defence = 5;
}

// 특정 조건을 만족하는 몬스터를 찾는 함수
StatInfo* FindMonster()
{
	// TODO : Heap 영역에서 뭔가를 찾아봄
	// 발견 시
	// return monster~;

	return nullptr;
}

// StatInfo globalInfo;
// 주소 전달 방식
// [매개변수][RET][지역변수(info)][매개변수(&info)][RET][지역변수]
void PrintInfoByPtr(StatInfo* info)
{
	if (info == nullptr) // null 체크 (메모리 누수 방지)
		return;

	if (!info) // 비슷한 의미
		return;

	cout << "---------------------" << endl;
	cout << "HP: " << info->hp << endl;
	cout << "ATT: " << info->attack << endl;
	cout << "DEF: " << info->defence << endl;
	cout << "---------------------" << endl;

	// const를 * 뒤쪽에 붙이면
	// StatInfo* const info
	// info라는 바구니의 내용물(주소)을 바꿀 수 없는 상태가 됨
	// info는 주소값을 갖는 바구니 -> info 자체가 가지고 있는 주소값을 고정시키겠다는 의미
	//info = &globalInfo; // info[주소값] 변경이 불가해짐

	// const를 * 앞쪽에 붙이면
	// const StatInfo* info
	// info가 '가리키고 있는' 바구니의 내용물을 바꿀 수 없는 상태가 됨
	// info가 가지고 있는 주소값으로 이동하여 변경 불가
	// info->hp = 10000; // 주소값[데이터] 변경이 불가해짐
}

// 참조 전달 방식
// 참조에는 const가 붙어다니는 경우가 굉장히 많다.
void PrintInfoByRef(const StatInfo& info)
{
	cout << "---------------------" << endl;
	cout << "HP: " << info.hp << endl;
	cout << "ATT: " << info.attack << endl;
	cout << "DEF: " << info.defence << endl;
	cout << "---------------------" << endl;
}

// 언리얼에서도 애용하는 스타일
#define OUT
void ChangeInfo(OUT StatInfo& info)
{
	info.hp = 1000;
}

int main()
{
	StatInfo info;

	CreateMonster(&info);

	// 포인터 vs 참조
	// 성능면에서 완벽하게 동일함
	// 편의성으로는 참조가 앞서고있음 (일반 값 전달 방식과 동일하게 표현됨)

	// 1) 편의성
	// 포인터는 주소를 넘기니 개발자의 관점에서 확실하게 원본을 넘긴다는 것을 알 수 있는데,
	// 참조는 자연스럽게 모르고 지나칠 수 있음
	// 함수 내부에서 원본값 수정이 필요치 않다면 const를 붙여 상수화하는것이 안전함

	// 2) 초기화 여부
	// 참조 타입은 바구니의 2번째 이름 (별칭)
	// -> 참조하는 대상이 없으면 안됨
	// 반면 포인터는 어떠한 주소라는 의미
	// -> 대상이 실존하지 않을 수 있음
	// 참조 타입은 nullptr과 같은 표현식이 없음
	// FindMonster() 참고

	// 포인터에서 없다는 의미로 선언하려면?
	StatInfo* pointer = nullptr; // null 포인터 선언
	// StatInfo* pointer; 가능
	pointer = &info;
	PrintInfoByPtr(pointer);

	// StatInfo& reference; 불가
	StatInfo& reference = info;
	PrintInfoByRef(reference);

	// 결론은
	// Team by Team
	// 구글 오픈소스는 거의 포인터를 사용
	// 언리얼에서는 레퍼런스도 애용
	// null값이 꼭 필요한게 아니라면 스타일에 따라 다른것임

	// Rookiss님 선호 스타일
	// - 없는 경우도 고려해야한다면 pointer (null 체크 필수)
	// - 바뀌지 않고 읽는 용도(readonly)만 사용하면 const ref&
	// - 그 외 일반적으로 ref (명시적으로 호출할 때 OUT을 붙임)
	// -- 단, 다른 사람이 pointer로 만들어둔걸 이어서 만든다면, 계속 pointer 사용 (섞어서 X)

	// 언리얼에서도 애용하는 스타일
	// 원본이 변경 될 수 있다는 힌트를 주는 스타일
	ChangeInfo(OUT info);

	// 포인터로 사용하던걸 참조로 넘겨주려면? *
	// pointer[주소(&info)]           ref, info[데이터]
	PrintInfoByRef(*pointer);

	// 참조로 사용하던걸 포인터로 넘겨주려면? &
	// pointer[주소]           reference, info[데이터]
	PrintInfoByPtr(&reference);

	return 0;
}

[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 - 인프런 | 강의
 
C++ 카테고리의 글은 인프런 Rookiss님의 강의를 공부하며 정리하는 내용입니다.
이미 알고 있는 내용도 다시 정리 되어있을 수 있습니다.

 

모든 글은 제가 공부하기 위해 작성합니다.

'Develop > C++' 카테고리의 다른 글

[C++] 포인터 vs 배열  (0) 2022.07.11
[C++] 배열 기초  (0) 2022.07.11
[C++] 참조 기초  (0) 2022.07.10
[C++] 포인터 실습  (0) 2022.07.05
[C++] 포인터 연산  (0) 2022.07.01