EC++ 3. const의 사용

반응형

const를 사용하여 싱글톤 객체를 생성할때
#include "../Core/Render/MgDevice.h"
MgDevice* const g_pDevice = MgDevice::GetInstance();

이와같이 만들어 주었다.

이로인해 define을 대신하여 const를 사용해 줌으로써 얻는 몇가지 이점이 있었다.
우선 귀차니즘이 강한 나로서 가장 큰 이점은 사용의 편리함이었다.
매크로는 단지 매크로일 뿐이기 때문에 변수로 취급되지 않아 자동완성 기능을
제공하지 않아 항상 멤버를 보기 위해 해당파일을 찾아봐야 하지만
const는 변수로 만들면 자동완성을 제공해 준다.

위의 의미는 상수포인터, 비상수 데이터라는 의미이다.
내가 원한것은 객체의 주소는 pix하게 하고 내부 데이터는
고칠수 있도록 하는 것이었다.

만약 const MgDevice* const g_pDevice = MgDevice::GetInstance();
와 같이 하였다면, 내부 멤버들도 const를 사용해야 했을 것이다.

const는 stl의 iterator에서도 잘 사용된다.
사실 나는 사용해 본적이 없다.
const std::vector<int>::iterator iter = vec.begin();
이런식으로 사용하면 되는데 아직 사용의 필요성을 느끼지 못했다.
이를 이용하면
*iter = 10; 과 같이 가리키는 대상의 변경은 가능하지만
++iter;      과 같이 객체 자체는 변경이 불가능 하다.

사실 const가 가장 빛나는 곳은 함수 선언부 이다.
const를 사용하여 함수의 반환값, 매개변수등을 조절하여 사용시 에러를 줄일 수 있다.

a. CDump& CDump::Func(const char* pt);
b. CDump& CDump::Func(char* const pt);
c. const CDump& CDump::Func(char* pt);
d. CDump& CDump::Func(char* const pt) const;

네개의 예가 있지만 조합하면 더 많은 경우가 나온다.
a - pt가 가리키는 데이터를 수정할 수 없다. 하지만 pt자체가 다른 문자열 주소를 받을 수는 있다.
     비상수 포인터, 상수 데이터가 된다.

b - 위와 반대경우로 다른 문자열 주소는 받을 수 없지만 데이터는 변경이 가능하다.
     상수 포인터, 비상수 데이터가 된다.

c - 리턴되는 객체가 const화 된다.

d - 이 메소드를 처리하는 동안 자신의 객체를 const화 한다.
     즉, 이 메소드를 처리하는 동안 객체의 모든 데이터를 수정할 수 없다는 의미이다.

c와 d의 차이는 시점의 차이라고 볼 수 있는데 c는 메소드내에서는 모든 데이터를 수정 가능하지만
리턴된 객체로 처리할 때는 const가 되는 것이며 d는 메소드 내에서는 수정불가능 하지만
리턴 된 이후에는 수정 및 가공이 가능하다.

멤버 함수에 붙는 const의 역활은 "해당 멤버 함수가 상수 객체에 의해 호출될 함수"라는 것을 알려주는 것이다.
이를 통해 두가지 이점을 얻을 수 있다.
1. 클래스의 인터페이스 가독성을 높여 클래스로 만들어진 객체를 변경할 수 있는 함수와 변경할 수 없는 함수를 구분해 준다.
2. 상수 객체의 사용 - 객체 전달을 "상수 객체에 대한 참자조"로 하면 실행 성능을 높일 수 있다.

사실 오래전에 어떤 코드를 보며 의아해 했던 적이 있었다.
분명 같은 함수명에 같은 파라미터를 가지는데 중복 선언이 가능했던 것이다.
그 두 함수의 차이점은 단지 const가 붙어있고 없고의 차이였다.
지금와서야 const 키워드가 있고 없고의 차이만으로 멤버함수의 오버로딩이 가능 하다는걸 알게 되었다.



예는 이 파일로 대신한다. :  
비트수준 상수성과 논리적 상수성에 대한 것도 이야기가 나오지만
컴파일러가 바뀐건지 전체 const를 걸고 해당부분을 리턴하는 작업은 허용되지 않았다.
그래서 그냥 주석처리..ㅡㅡ;..

그리고 추가로 나와주는 mutable의 존재.
이녀석은 단지 비정적 데이터 멤버를 비트수준 상수성에서 벗어나게 해주는 역활을 한다.
이녀석도 그다지 써본일이 없지만....정말 거의 없다..

어차피 처음부터 설계를 정말 잘 했다면 굳이 mutable를 쓸 필요가 없지않을까...

그리고 mutable와 항상 비교되는 녀석....const_cast..
캐스팅 자체가 썩 좋은것은 아니지만 상수버전과 비상수 버전의 중복코드 문제도 만만치 않기때문에
이를 처리해주기 위해 간단한 아이디어로 비상수 버전의 함수에서 상수버전의 함수를 호출하는 방식을 사용한다.

즉, 비상수버전에서 객체에 const를 씌운다음 상수버전을 호출가능하게 하여 상수버전을 호출하고,
리턴된 것을 수정가능버전인 비상수버전으로 만들기 위해 const_cast를 사용하여 const의 껍질을 벗겨낸다.

물론 반대로 상수에서 비상수로의 호출도 가능하긴 하지만 좀 복작하며 안전성의 문제가 뒤따른다.
논린적으로 상수로 정의하기로 한것을 다시 변수로 바꾼다는 것 자체가 속상한 일이지 않을까...

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

3d좌표 2d좌표로 변환  (0) 2009.09.02
EC++ 4. const의 사용 - 수정중  (0) 2009.09.02
pragma 정리  (0) 2009.08.01
About Interlocked  (0) 2009.08.01
메모리 관리  (0) 2009.07.31
TAGS.

Comments