1. 포인터는 재할당 할 수 있습니다.
1 2 3 4 5 6 7 8 | int x = 5; int y = 6; int* p; p = &x; p = &y; *p = 10; assert(x == 5); assert(y == 10); |
레퍼런스는 무조건 초기화 할 때 할당 해줘야 합니다.
1 2 3 | int x = 5; int y = 6; int& r = x; |
2. 포인터는 스택에 자신 고유의 주소를 가지고 있지만 (x86 운영체제에서 4 바이트), 반면 레퍼런스는 원본 변수와 같은 메모리 주소를 공유하면서 스택 공간에 자리를 차지합니다. 레퍼런스가 원본 변수랑 같은 주소를 공유하니깐 그냥 레퍼런스를 원본의 또 다른 이름이라고 생각하면 됩니다. 참고로 포인터가 가르키는 것은 스택뿐만 아니라 힙에 있을 수 있습니다. 레퍼런스도 마찬가지입니다. 여기서 내가 말하고자 한건 포인터는 무조건 스택을 가르킬 필요는 없다는 것입니다. 포인터는 단지 메모리는 주소를 담는 변수일 뿐입니다. 이 변수는 스택에 있습니다. 레퍼런스는 스택에 자신만의 공간이 있고 주소는 참조하는 변수랑 같습니다.
이건 컴파일러가 알려주지 않는 레퍼런스의 진짜 주소가 있다는걸 알려줍니다.
1 2 3 4 5 | int x = 0; int& r = x; int* p = &x; int* p2 = &r; assert(p == p2); |
3. 포인터의 포인터의 포인터처럼 여러번 참조하는 방식을 쓸 수 있는 반면에 레퍼런스는 한 번만 참조 할수있습니다.
1 2 3 4 5 6 7 8 9 | int x = 0; int y = 0; int* p = &x; int* q = &y; int** pp = &p; pp = &q; //*pp = q; **pp = 4; assert(y == 4); assert(x == 0); |
4. 포인터에는 직접적으로 nullptr을 할당할 수 있는데 레퍼런스는 그렇게 못합니다. 하지만 특정한 방법으로 레퍼런스의 주소를 nullptr로 만들수 있긴 합니다.
1 2 3 | int* p = nullptr; int& r = nullptr; //컴파일 에러 int& r = *p; //컴파일 잘된당, 특히 nullptr가 함수 호출 뒤에 감춰져 있을때. 주소 0을 갖고 있고 존재하지 않는 int를 참조하게 된다. | cs |
5. 포인터는 배열을 iterate 할 수 있습니다. ++ 연산을 이용해서 포인터가 가르키는 곳의 다음 곳을 가르킬 수 있고, +4 를 이용하면 5번째 원소를 가르킬 수 있다. 가르키는 객체의 크기에 상관 없이 할 수 있습니다.
6. 레퍼런스는 다른 작업 없이 바로 쓸 수 있는데 포인터는 * 로 가르키는 메모리 공간에 접근 할 수 있습니다.
7. 포인터는 메모리 주소를 담는 변수입니다. 레퍼런스는 어떻게 선언되었든, 참조하고 있는 객체와 같은 메모를 주소를 갖습니다.
8. 레퍼런스는 배열에 넣을 수 없지만 포인터는 넣을 수 있습니다.
9. const 레퍼런스는 임시 변수를 참조 할 수 있습니다. 포인터는 그럴 수 없습니다.
1 2 | const int& x = int(12); // 오케이 int* y = &int(12); // 에러 |
const&를 argument list에서 더 안전한게 쓸 수 있습니다.
'공부 > C++ \C#' 카테고리의 다른 글
C++ 프로그래밍 : 런타임 타입 정보(Runtime Type Information) (0) | 2020.06.03 |
---|---|
인라인 (Inline) (0) | 2018.08.08 |
vector의 size와 capacity (0) | 2018.07.04 |
사용되지 않음 #pragma deprecated (0) | 2018.05.11 |
volatile 키워드 (0) | 2018.05.11 |