캐스팅 절약(effective c++ 27)

2015. 9. 4. 16:31프로그래밍/Effective C++

728x90
728x90

C++의 캐스팅이란?

어떤 일이 있어도 타입 에러가 생기지 않도록 보장한다.

이론적으로 C++ 프로그램은 컴파일만 끝나면 그 이후엔 어떤 객체에 대해서도 불안전한 연산이나말도 안되는 연산을 수행하려 들지 않는다.


문제점
캐스트( cast )는 C++의 동작 규칙을 무시 할만한 기능을 갖고 있다.
C++에서 캐스팅은 정말로 조심해서 써야 하는 기능이다.

C++ 스타일 캐스트
const_cast
객체의 상수성( constness )을 없애는 용도로 사용된다. 
이런 기능을 가진 C++ 스타일의 캐스트는 이것 밖에 없다.
객체의 휘발성( volatileness )을 제거하는 용도로도 쓰인다.

dynamic_cast
'안전한 다운 캐스팅( safe downcasting )'을 할 때 사용하는 연산자이다.
주어진 객체가 어떤 클래스 상속 계통에 속한 특정 타입인지 아닌지를 결정하는 작업에 쓰인다.
구형 스타일 캐스트 문법으로는 흉내 낼 수 없는 유일한 캐스트이다.
런타임 비용이 높은 캐스트 연산자로도 유일하다.

reinterpret_cast
포인터를 int로 바꾸는 등 하부 수준 캐스팅을 위해 만들어진 연산자이다.
적용 결과는 구현 환경에 의존적이다( 이식성이 없다 )
이런 캐스트는 하부 수준 코드 외에는 거의 없어야 한다.

static_cast
암시적 변환( 비상수 객체를 상수 객체로 , int를 double로 바꾸는 등  )을 강제로 진행할 때 사용한다.
타입 변환을 거꾸로 수행하는 용도( void*를 일반 타입의 포인터로 바꾸거나, 
기본 클래스의 포인터를 파생 클래스의 포인터로 바꾸는 등 )로도 쓰인다.
상수 객체를 비상수 객체로 캐스팅하는데 사용할 수 없다( const_cast 연산자만 가능 )

dynamic_cast의 문제점
상당수의 구현 환경에서 이 연산자가 정말 느리게 구현되어 있다.

문제점 예시
어떤 구현 환경의 경우, 클래스 이름에 대한 문자열 비교 연산에 기반을 두어 dynamic_cast가 만들어져 있다.
예를 들어 깊이가 4인 단일 상속에 속한 어떤 객체에 대해 이 연산자를 적용할 때, 
클래스의 이름을 비교하기 위해 strcmp가 최대 네 번 까지 불릴 수 있다.
상속의 깊이가 더 깊거나 다중 상속이라도 쓰게 되면 그 비용이 더 커질 것이다.

dynamic_cast를 피해보자!
언제 쓰고 싶은가?
파생 클래스 객체임이 분명한 녀석이 있어서, 이에 대해 파생 클래스의 함수를 호출하고 싶은데, 
그 객체를 조작할 수 있는 수단으로 기본 클래스의 포인터( 혹은 참조자 ) 밖에 없을 경우

방법1.
파생 클래스 객체에 대한 포인터( 혹은 스마트 포인터 )를 컨테이너에 담아둠으로써
각 객체를 기본 클래스 인터페이스를 통해 조작할 필요를 없애 버리는 것이다.

여기서 이렇게 해버리면 엄청난 오버헤드가!


이렇게 dynamic_cast를 없앨 수 있다.

문제점
Window에서 파생될 모든 녀석들에 대한 포인터를 똑같은 컨테이너에 저장할 수 없다.
기본 클래스 인터페이스를 통해 조작할 수 있는 방법은 가상 함수로 제공하는 것이다.

방법2.
가상 함수를 기본 클래스로 올려 기본 클래스 인터페이스를 통해 조작할 수 있게 한다.


정리

캐스팅 써야하나요?

정말 잘 작성된 C++ 코드는 캐스팅을 거의 쓰지 않는다.

하지만 캐스팅을 아예 안쓰는 것은 좋은 생각은 아니다. 상황에 따라서 사용할 것.


캐스팅 꼭 필요한가요?
int를 double로 바꾸는 경우는 터무니 없는 캐스팅은 아니다.( 엄밀히 따지면 꼭 필요한가에 대한 의문이 남긴 하다 )
철저히 따져 보면서 캐스팅을 하자.

캐스팅은 언제 쓰나요?
막 쓰기에는 꺼림칙한 문법 기능을 써야 할 때 흔히 쓰이는 수단을 활용해서 처리하는 것이 좋다.
캐스팅을 하는 코드를 내부 함수 속에 몰아 놓고 외부에서 알 수 없도록 인터페이스로 막아두는 식으로 사용하는 것이 좋다.

이것만은 잊지 말자
다른 방법이 가능 하다면 캐스팅은 피하자. 특히 수행 성능에 민감한 코드에서 dynamic_cast는 몇 번이고 다시 생각하자. 
설계 중에 캐스팅이 필요해졌다면, 캐스팅을 쓰지 않는 다른 방법을 시도하자.

캐스팅이 어쩔 수 없이 필요하다면, 함수 안에 숨길 수 있도록 하자.이렇게 하면 최소한 사용자는 자신의 
코드에 캐스팅을 넣지 않고 이 함수를 호출 할 수 있게 된다.

구형 스타일의 캐스트를 쓰려거든 C++ 스타일의 캐스트를 선호하자. 
발견하기도 쉽고, 설계자가 어떤 역할을 의도했는지가 더 자세하게 드러난다.



728x90
반응형