Post List

2015년 3월 27일 금요일

item 06: auto 가 문제 될 때는 명시적 타입으로 초기화하자.

작가
Meyers, Scott
출판
O'ReillyMedia
발매
2014.12.12
평점








Effective Modern C++ - Scott Meyers
Item 6 : Use the explicitly typed initializer idiom when auto deduced undesired types.

item 6. auto 가 문제 될 때는 명시적 타입으로 초기화하자.

item 5에서 auto를 극찬해 놓고는, 찬물을 끼얻고 있다.
하지만, 중요한 내용이니 한번은 알고 넘어가는게 좋을듯 하다.

* using auto on Proxy Class

template<typename T>
std::vector<bool> ConvertBit(const T& Obj);

void ProcessBit(Widget W, bool b)
{
    std::cout << b << std::endl;
};

Widget W;
bool bit5 = ConvertBit(W)[4];
ProcessBit(W, bit5);          // OK

auto bit6 = ConvertBit(W)[5];
ProcessBit(W, bit6);          // Run-time error (Dangling Pointer)

위 Code에서 bit5는 bool로 받아서 처리했더니 문제가 없었다. 뭐 당연하겠지.
그런데, bit6는 auto로 받아서 처리했더니 런타임에서 오류가 발생했다.
왜 그럴까 ?
조금 복잡할 수도 있다. 심호흡 한번 하고 살펴보자.

STL의 std::vector<T>는 std::vector<bool>를 제외하고는 [ ] (인덱스 연산자)에서 T&를 반환한다.
하지만, C++ 규칙상 Bit 단위의 참조는 사용 할 수가 없다.
그래서 std::vector<bool>의 경우 각 요소별로 1 Bit씩 저장하여 사용 공간을 줄이기 위해서,
다른 타입들과는 좀 다르게 처리가 된다.
bool이 아니라 std::vector<bool>::reference을 반환한다. (std::vector<bool> 내부에 정의된 class)
bool로 받은 bit5는 Value 로 전달받아서 ConvertBit(W)에 의해 생성된 R-Value std::vector<bool>가 사라져도 값이 유지 되는데,
auto로 받은 bit6는 std::vector<bool>::reference라서 R-Value std::vector<bool>가 사라지면,
Dangling Pointer가 되어서, 다음줄에서 사용할 때는 문제가 된다.

std::vector<bool>::reference와 같이 원래 행동을 숨기는 classProxy class 라고 한다.
(디자인 패턴 참조)
Proxy class에 auto를 사용하는 건 문제가 될 수 있다.
라이브러리 해더 파일을 보면 Proxy class로 구현되었는지 알 수가 있으니깐, 참조하면 된다.
(그걸 헤더파일에까지 숨기는 경우는 잘 없다.)

이런 경우는 명시적으로 타입 변환을 해주는 방법이 있다.

auto bit6 = static_cast<bool>(ConvertBit(W)[5]);

조금 웃프긴하다. 저럴빠에야 그냥 bool로 선언하고 말지...
과연 저렇게까지 해서 auto를 쓰는게 무슨 의미가 있을까 ???
static_cast<bool>의 타입추론 결과가 bool이 아닐 수 있나 ?
지금은 그렇지 않지만, 혹시 뭐 나중에 어떻게 바뀔지는 모르는 일이니깐,
그냥 그렇다고 알고 넘어가자.
(난 저렇게 절대 안쓰고 걍 bool을 쓸것이다.)

Things to Remember

* Invisible Proxy Pattern에 auto를 사용할 때 잘못된 추론을 할 수도 있다.

* 명시적 타입 추론을 하면 auto는 제대로 추론될 것이다.
  (그럴빠에 난 그냥 그 타입을 사용하겠다.)

댓글 없음:

댓글 쓰기