책 정리/Effective C++ 3rd

항목 3. 낌새만 보이면 const를 들이대 보자!

ocean20 2019. 12. 10. 12:02

 

상수성에 대해 알아보기위해 연산자 정의 코드를 살펴보자.

const Complex operator +(const Complex &T) const
{       
  Complex R;        
  R.image = image + T.image;       
  R.real = real + T.real;            
  return R;
}

1. 인수를 레퍼런스로 넘기는이유

  (1) 크기 때문에 비효율적이므로 레퍼런스로 넘기는 것이 유리하다.

  (2) 직관적 표현을 위해서

    1) 포인터로 넘기는경우 c3 = c1 + &c2 이런 형태가 될 것이다.

 

2. 인수의 상수성

  (1) a+b인 경우, 인수로 전달되는 우변의 값을 변경하는 경우는 전혀 없으며, 단지 읽기만 한다

      즉, const 지정자를 붙이는 것이 안전하다.

 

  (2) 안붙인다면?

const complex c2(1.0, 2.0);

c3 = c1 + c2 //불가능함

 

3. 함수의 상수성

  (1) 호출 객체의 상태를 바꾸지 않을 경우는, 원칙에 따라 const 함수로 지정하는 것이 좋다.

      이항 연산자들은 객체의 값을 읽기만 할 뿐 객체를 변경하지 않는다.

const int i=4;

int j=3,k;

k=i+j;

  (2) 함수의 상수성이 없다면 위 코드가 동작할 수 없다.

  (3) 반면 객체의 값을 직접 변경하는 연산자( =, ++ 등) const로 지정해서는 안된다.

 

4. 리턴 타입의 상수성

int i=3,j=4,k;

k=i+j;

  (1) i+j의 결과로 리턴되는 값은 7이라는 정수 상수이지 정수형 변수가 아니다.

    만약 i+j가 값을 변경할 수 있는 정수형 변수를 리턴한다면 i+j=5;라는 연산식도 허용되어야 할 것이다.

 

참고사이트 : http://soen.kr/


이제 effective c++ 로 돌아와보자.

 

1. const 면모

  (1) const 키워드가 붙은 객체는 외부 변경이 불가능하다.

const char * const p= greeting;

  (2) const 키워드가 *왼쪽에 있을경우 포인터가 가리키는 대상이 상수 ( 해당 주소에 들어있는 변경이 X)

  (3) * 오른쪽에 있을경우 포인터 자체가 상수(포인터의 주소값을 변경할 x)

 

2. 리턴타입의 상수성

( a * b ) = c;

이항 연산자에서 리턴타입이 상수성을 가지지 않는다면 위와 같은 대입이 가능해진다.

 

3. 상수 멤버 함수

  (1) 상수멤버함수가 중요한이유?

    1) 해당 클래스로 만들어진 객체를 변경할 있는 함수가 무엇인지 알수있음 -> 클래스의 인터페이스를 이해하기

    좋게함(참고 : 상수멤버함수는 해당 클래스의 데이터들을 변경할 없다.)

 

    2) c++ 성능을 높이는 reference to const(ex. const &char) 진행하려면, 상수멤버함수가 준비되어있어야 한다.

    (참고 : const 키워드 있고 없고의 차이만 있는 멤버 함수들은 오버로딩이 가능함.)

 

4. 물리적 상수성 vs 논리적 상수성

  (1) 물리적 상수성 : 어떤 멤버함수가 객체의 어떤 데이터멤버도 건드리지 않아야 한다. (정상적인 아래 코드)

class CTextBlock{
public :
  …
  char& operator[](std::size_t position) const
  {return pText[position]; }

private :
  char *pText;
};

  (2) 비트적 상수성은 지켜지나 논리적 상수성이 필요한 코드

const CTextBlock cctb("hello");

 char *pc = &cctb[0];

*pc = 'J';   // 비트수준의 상수성은 지켜지나..

  (3) 논리적상수성

    1) 이러한 황당한 상황을 보완하는 개념 : mutable

private :
  char *pText;
  mutable std::size_t textlength;
  mutable bool lengthIsValid;

 //mutable 사용할시, 상수멤버함수에서 데이터멤버를 변경할수있다.
std::size_t Ctextblock::length() const
{
  if(!lengthIsValid){
    textLength = std::strlen(pText);
    lengthIsValid = true;
  }
  return textlength;
}

 

이것만은 잊지말자!

1. const 붙여 선언하면 컴파일러가 사용상의 에러를 잡아내는데 유용하다! (리턴타입, 매개변수, 멤버함수, 객체에 붙일 있음)

2. 컴파일러쪽에서보면 비트수준상수성을 지켜야하지만, 우리는 논리적인 상수성을 사용해서 프로그래밍해야함.

3. 상수멤버 비상수멤버함수가 서로똑같이 구현된경우, 코드중복을 피하는것이 좋다. -> 비상수버전에서 상수버전을 호출하도록 하자! ==> 추후 업데이트