Skip to content

2주차 스터디 const사용

abiles edited this page Oct 22, 2014 · 10 revisions
//effective c++, soen.kr에 있는 내용을 정리했습니다. 

키워드 const를 알아보자

  • 지금까지 코딩을 하면서 많은 const 키워드를 만났지만 그 의미를 잘 몰라서 쓰기가 두려웠기 때문에

    이번 기회에 알아보려고 합니다.

의미

  • const는 constant에서 왔습니다. 수학 용어로 '상수'를 나타냅니다.

    다시 '상수'는 변하지 하지 아니하는 일정한 값을 가진 수라고 정의 할 수 있습니다.

이점

  • const 키워드를 통해서 3가지 이점를 가질 수 있습니다.
    1. 의미적인 제약(const 키워드가 붙은 객체는 외부 변경을 불가능하게 한다)을 소스코드 수준에서 붙일 수 있다.
    2. 이 제약을 컴파일러가 단단히 지켜준다.
    3. 어떤 값(객체의 내용)이 불변이어야 한다는 제작자의 의도를 컴파일러 및 다른 프로그래머와 나눌 수 있다.

const의 일반적인 사용

  • const의 기본 형식은 다음과 같습니다.

    const 타입 변수명 = 초기값;

    변수 선언과 비슷하지만 앞에 const를 붙이고 뒤에 반드시 초기값을 적어야 한다는 점이 다릅니다.

    하지만 일반적으로 쓸 때

    const 타입 변수명 = 초기값;은

    타입 const 변수명 = 초기값; 과 같은 역할을 합니다.

  • const를 포인터 혹은 레퍼런스(참조자)와 함께 사용할 때

  • const의 위치를 포인터나 연산자 기준으로 생각합니다. 즉 const가 포인터의 왼쪽이냐 오른쪽이냐에 따라 의미가 다릅니다.

    • const * 인 경우(const가 포인터의 왼쪽에 위치한 경우) 이 때는 가리키는 대상이 상수가 됩니다.
//
int levelArr[] = {1,2,3,4,5};
const int* cAge = &levelArr[0];
*cAge = 6(x)
cAge++(O)
  • 포인터 const 인 경우 이 때는 포인터 자체가 상수가 됩니다.
//
int levelArr[] = {1,2,3,4,5};
int* const cAge = &levelArr[0];
*cAge = 6(0)
cAge++(x)

이중포인터에서의 const 사용

  • 이중 포인터에 오면 const의 사용 방법이 꽤 헷갈립니다.
  • 이중 포인터에서 const가 놓이는 위치는 총 3 곳입니다.
//이중 포인터에 const 붙이기
const int * const * const ppi;
//1번       2번      3번
  • 단일 포인터에 const 붙이던 것을 생각해 봅시다. const는 두 가지중 하나입니다.

    포인터 자체를 상수로 하거나, 포인터가 가리키는 대상을 상수로 하거나.

  • 위 const에 번호를 붙이겠습니다. 왼쪽부터 차례대로 1번 const, 2번 const, 3번 const입니다.

  • 1번 const는 ppi가 가리키는 포인터가 가리키는 int 값을 상수화 합니다. (가리키는 대상 상수화)

  • 2번 const는 ppi가 가리키는 포인터를 상수화 합니다. (가리키는 대상 상수화)

  • 3번 const는 ppi 자신을 상수화 합니다. (자신 상수화)

  • 결국 단일 포인터의 const 사용의 확장입니다.

  • 아래 예제가 굉장히 훌륭합니다.

 예 제 : ConstDblPointer
#include <Turboc.h>
 
void main()
{
     int i=5;
     int *pi=&i;
     const int *pci;
     int * const cpi=&i;
     const int * const cpci=&i;
 
     // 일반 이중 포인터 - 모두 가능
     int **ppi1=&pi;
     ppi1++;
     (*ppi1)++;
     **ppi1=0;
 
     // 상수 지시 포인터의 포인터
     const int **ppi2=&pci;
     ppi2++;
     (*ppi2)++;
//  **ppi2=0;      // 에러 : 최종 대상체(정수) 변경 불가
 
     // 비상수 지시 상수 포인터의 포인터
     int * const *ppi3=&cpi;
     ppi3++;
//  (*ppi3)++;     // 에러 : 중간 대상체(포인터) 변경 불가
     **ppi3=0;
 
     // 비상수 지시 비상수 포인터의 상수 포인터
     int ** const ppi4=&pi;
//  ppi4++;              // 에러 : 포인터 자체 변경 불가
     (*ppi4)++;
     **ppi4=0;
 
     // 상수 지시 상수 포인터를 지시하는 상수 포인터 - 전부 에러
     const int * const * const ppi5=&cpci;
//  ppi5++;
//  (*ppi5)++;
//  **ppi5=0;
}

함수에서의 const사용

  • effective c++의 수식어를 옮기자면 뭐니뭐니해도 가장 강력한 const의 용도는 함수 선언에 쓸 경우입니다.

    함수 선언에 쓰는 경우는 총 4가지로 나눌 수 있습니다.

  1. 함수의 반환 값에 쓰는 경우

  2. 매개변수에 쓰는 경우

  3. 멤버 함수에 쓰는 경우

  4. 함수 전체에 대해 const를 붙이는 경우

  • 함수의 반환 값에 쓰는 경우(1)
const int& foo();
  • 반환 값에 const가 쓰이는 경우는 레퍼런스(참조값)나 포인터로 쓰일 때가 아니라면 별 의미가 없습니다.

  • 반환 값에 const가 쓰이면 반환되는 레퍼런스가 상수로 취급 되고 변화 될 수 없음을 뜻합니다.

  • 매개 변수에 const가 쓰이는 경우는 지역 변수에 const를 사용하는 것과 동일합니다. (2)

    함수 내에서 값을 변경할 수 없게 됩니다. 실제 const 사용의 예를 하나 보겠습니다.

void print(const TextBlock& ctb) // 이 함수에서 ctb는 '상수 객체'로 쓰입 니다. <- 상수객체 기억!

std : : cout << ctb [0] ; // TextBlock : : operator [] 의 상수
...
}

상수객체는 (1)상수 객체에 대한 포인터 혹은 (2) 상수 객체에 대한 참조자로 객체가 전달 될때 생기게 됩니다.

상수 객체는 상수 멤버 함수만를 사용할 수 있습니다. 일반 객체는 모든 멤버 함수를 다 사용할 수 있습니다.(public이라면)

  • 멤버 함수에 쓰는 경우(3)

    멤버 함수를 선언할 때 const를 붙여주는 경우 입니다. 이 경우 해당 함수 내부에서는 멤버 변수를 변경할 수 없습니다.

    또 const 선언을 통해 클래스 멤버 함수중 무엇이 멤버변수를 변경할 수 있는 녀석인지 사용자가 알기 쉬워집니다.

    또 멤버 함수에 const를 붙이는 것으로 함수를 오버로딩 할 수도 있습니다.

    멤버함수가 상수 멤버함수가 되면 이는 비트수준의 상수성(물리수준의 상수성)을 지켜야 합니다.

    이는 어떤 멤버함수가 그 객체의 어떤 데이터 멤버도 건드리지 않아야(정적멤버 제외) 그 멤버함수를 const로

    인정하는 개념입니다. 즉 그 객체를 구성하는 비트들 중 어떤 것도 바꾸면 안 된다는 것입니다.

//멤버함수 const 오버로딩의 예

class TextBlock {
public :
const char& operator[] (std: :size_ t position) const  //상수 객체 에 대 한
{ return text[position); } // operator []
char& operator (std : : size_ t position) //비 상수 객체 에 대 한
{ return text[position] ; }// operator []

private :
std : : string text ;
};
  • 함수 전체에 대해 const를 붙이는 경우( 무슨 말인지 모르겠습니다. effective c++에도 별다른 설명이 없습니다)(4)

const_cast에 대한 설명

  • const를 붙여주는 일은 const가 하고 있습니다. 따라서 const_cast는 const를 떼어내는 일만 합니다.

  • const_cast < type-id > ( expression ) 이 방식으로 씁니다.

const int* cInt = new int(10);

//cInt의 상수성을 제거하면서 pInt로 주소값을 넘깁니다. 
int* pInt = const_cast<int*>(cInt);
//따라서 pInt는 새 정수값을 넣을 수 있게 됩니다. 
*pInt = 200;

마무리

const에 대한 설명을 다음으로 마칩니다.

const는 우발적인 코드로부터 중요한 값을 보호하는 문법적 장치이므로 안정성을 위해 적극 활용하는 것이 좋다.

일부 코드는 const를 쓰고 일부 코드는 쓰지 않으면 타입이 맞지 않아 인수 전달이 원활하지 못한 부작용이 있다.

특히 팀 프로젝트는 서로의 스타일이 다르면 골 때리는(!!) 상황이 발생할 수 있는데

이런 경우는 가급적 원칙대로 const를 철저하게 지키는 것이 바람직하다.

객체 지향 프로그래밍 기법에서는 const가 더욱 중요한 역할을 하는데

const로 지정된 멤버 함수는 클래스 내부를 함부로 변경할 수 없으므로

객체의 안전성을 지키는 중요한 역할을 한다.

Clone this wiki locally