[포인터 기초 #1]

 

포인터 변수는 타입에 상관없이 4바이트(32비트 환경) or 8바이트(64비트 환경) 고정 크기이다.

디스어셈블리로 확인해보면 포인터 값을 참조하는 경우 mov를 두번 타고 넘어가서 값을 가져오게 된다. 

 

변수 : 값을 담는 바구니

포인터 변수 : 주소를 담는 바구니

 

[포인터 기초 #2]

 

포인터 변수는 타입에 상관없이 크기 고정이면 왜 타입을 지정할까?

-> 포인터의 타입보다는 가리키고 있는 주소의 타입이 어떤건지 알려주는 준다고 보면 된다.

 

가리키는 주소의 범위를 넘겨서 데이터를 잘못 조작하면 치명적인 문제가 발생할 수 있다. (타입의 불일치)

예) int형 변수를 __int64로 캐스팅한 주소를 받아서 8바이트 데이터를 대입하는 경우.

 

[포인터 연산]

 

주소 연산자 (&) : 해당 변수의 주소를 알아냄

산술 연산자 (+, -) : 타입의 크기만큼 주소 증감

간접 연산자 (*) : 주소가 가리키는 값에 접근

간접 멤버 연산자 (->) : 간접 연산자와 . 연산을 한큐에 함. (*ptr).a = 1과 ptr->a = 1은 어셈블리상 완벽하게 동일하다.

 

[포인터 실습]

 

구조체(클래스)를 반환하여 값을 초기화 하는 방식은 임시 공간을 만들어서 함수를 빠져나올 때 임시 공간에 있는 값을을 전부 복사해서 넘겨준다는 것을 레지스터를 통해 확인할 수 있다. (오버헤드 발생)

 

포인터를 넘겨줘서 간접 참조로 초기화 하면 임시 공간을 사용하지 않기 때문에 훨씬 효율적이다.

 

구조체(클래스)끼리 복사하는 경우 각 인자를 복사하는 것과 다름없다.

 

[참조 기초]

 

1) 값에 의한 전달 (Call by value) : 구조체/클래스의 크기에 따라 오버헤드가 크게 발생

2) 주소에 의한 전달 (Call by address) : 언제나 4-8바이트만 사용

3) 참조에 의한 전달 (Call by reference) : 로우레벨(어셈블리) 관점에서 실제 작동 방식은 주소에 의한 전달과 완벽하게 똑같음

 

참조에 의한 전달은 값에 의한 전달과 동일하게 사용하지만 작동 구조는 주소의 의한 전달로 이뤄져서 양쪽의 장점만을 빼온듯한 모양새이다.

 

[포인터 vs 참조]

 

성능적인 면에서는 완벽하게 똑같다.

편의성은 참조가 더 좋다고도 볼 수 있다.

 

편의성 관련

포인터는 주소를 명시적으로 넘기기 때문에 코드를 확인할 때 바로 확인할 수 있지만 참조는 값에 의한 전달인지, 참조에 의한 전달인지 겉으로 보기에는 티가 안난다. (휴먼에러 발생 가능성)

 

레퍼런스와 const는 세트로 등장하는 경우가 매우 많다.

 

const를 포인터에 붙일 때 * 앞에 붙는 경우 주소를 바꿀 수 없고 뒤에 붙는 경우 참조값을 바꿀 수 없다.

StatInfo globalInfo;

info = &globalInfo; // 매개변수가 const StatInfo* info 라면 사용 불가
info->hp = 10000; // 매개변수가 StatInfo* const info 라면 사용 불가

 

초기화 관련

포인터는 선언 시 초기화 하지 않아도 되지만 참조는 반드시 초기화 되어야 한다.

 

없는 값을 표현하는 경우 포인터는 nullptr이 있지만 참조는 그런게 없다.

웬만해서는 코드 실행전에 nullptr인지 아닌지 체크하는게 좋다.

실제로 프로그램이 뻗는 대부분은 null크래시이다.

 

결론

team by team이라서 정해진 답은 없다.

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

ex) 언리얼 엔진에서는 reference도 애용한다.

 

값이 없는 경우도 고려한다면 포인터, readonly만 한다면 const ref&.

다만 reference를 넘겨서 값이 변한다면 매개변수에 OUT이라는 명시를 해주는 방법이 있다.(언리얼에서 자주 사용)

가독성 차원에서는 바로 알아볼 수 있지만 기능면에서는 아무것도 없다.

#define OUT // 아무것도 정의하지 않음

void ChangeInfo(OUT StatInfo& info)
{
	// do something
}

// 함수 사용시
ChangeInfo(OUT info);

 

다만 딱히 정해진 규칙은 아니고 팀의 스타일에 따라가면 된다.

 

 

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

[객체지향 여행]  (0) 2022.08.28
[포인터] #2/2  (0) 2022.08.27
[함수]  (0) 2022.08.26
[코드의 흐름 제어]  (0) 2022.08.26
[데이터 갖고 놀기]  (0) 2022.08.25

+ Recent posts