const
키워드는 값을 상수로 선언할 수 있도록 도와주는 키워드 이다. 즉, 값을 변경할 수 없도록 한다.
const int a = 10;
a = 20; // error!
위 코드와 같이 한번 설정된 a는 read-only memeory에 올라가게 되고 변경할 수 없게 된다. 이처럼 const는 값을 한번 설정하고 그 값을 유지하면서 사용해야 할 때 필요하다.
상수를 가리키는 포인터가 가리키는 공간은 수정할 수 없는(const) 공간이지만 상수 변수의 주소를 가리키는 포인터는 수정할 수 있는(non-const) 포인터 이다.
int value = 5, value2 = 11;
const int * ptr = &value;
// *ptr = 10; // error! can't change const value
value = 10; // ok!
std::cout << value << " " << *ptr << std::endl; // 10 10
value = 7;
ptr = &value2;
std::cout << value << " " << *ptr << std::endl; // 7 11
위의 코드처럼 ptr
이라는 포인터는 변수 value의 주소를 가지고 있는 포인터 이다. 여기서 const는 const int*
가 아닌 const int
에 적용 되므로 포인터가 가리키고 있는 값을 바꿀 수는 없지만 주소값은 바꿀수 있다.
위에서 나왔던 포인터는 가리키는 값은 변경 불가능하지만 다른 변수의 주소값으로 변경이 가능했다.
상수 포인터
는 위에서 나왔던 내용과 달리 주소를 바꿀 수 없도록 되어 있다.
int value = 5, value2 = 11;
int* const ptr = &value;
*ptr = 10; // ok! can change non-const value
value = 10; // ok!
std::cout << value << " " << *ptr << std::endl; // 10 10
value = 7;
//ptr = &value2; // error! can't change pointer address
std::cout << value << " " << *ptr << std::endl; // 7 7
위의 결과 처럼 ptr의 주소를 변경하려고 하면 오류를 발생시킨다. 포인터가 상수이기 때문에 포인터 값을 변경할 수가 없다.
하지만 포인터가 상수이지 포인터가 가리키는 값은 상수가 아니기 때문에 *ptr = 10
과 같이 포인터가 가리키는 값을 변경하는 것은 가능하다.
int value = 5, value2 = 11;
const int* const ptr = &value;
//*ptr = 10; // error! can't change const value
value = 10; // ok!
std::cout << value << " " << *ptr << std::endl; // 10 10
value = 7;
//ptr = &value2; // error! can't change pointer address
std::cout << value << " " << *ptr << std::endl; // 7 7
위의 코드는 앞서 본 2가지 케이스를 합친 형태로 포인터가 가리키는 값도 상수이며 포인터 또한 상수로써 가리키는 값을 바꾸거나 다른 주소를 가리키도록 수정을 할수 없다.
이처럼 const 의 위치에 따라 동작하는 방식이 다르기 때문에 이를 유의해서 사용하는것이 중요하다.
int value = 5;
const int* ptr1 = &value; // ptr1으로 value값 수정불가능(상수), 주소값 변경 가능
int* const ptr2 = &value; // ptr2으로 value값 수정 가능, 주소값 변경 불가능(상수포인터)
const int* const ptr3 = &value; // ptr3으로 value 값 수정 불가능(상수), 주소값 변경 물가능(상수 포인터)
쉽게 이해하기 위해서 다음 처럼 이해할 수 있다.