KoreanFoodie's Study
Effective Modern C++ | 항목 6 : auto 가 원치 않은 형식으로 연역될 때는 명시적 형식의 초기치를 사용하라 본문
Effective Modern C++ | 항목 6 : auto 가 원치 않은 형식으로 연역될 때는 명시적 형식의 초기치를 사용하라
GoldGiver 2022. 10. 26. 09:50
C++ 프로그래머의 필독서이자 바이블인, 스콧 마이어스의 Modern Effective C++ 를 읽고 기억할 내용을 요약하고 있습니다. 꼭 읽어보시길 추천드립니다!
항목 6 : auto 가 원치 않은 형식으로 연역될 때는 명시적 형식의 초기치를 사용하라
핵심 :
1. "보이지 않는" 대리자 형식 때문에 auto 가 초기화 표현식의 형식을 "잘못" 연역할 수 있다.
2. 형식 명시 초기치 관용구는 auto 가 원하는 형식을 연역하도록 강제한다.
다음 예시를 보자.
class Widget {};
std::vector<bool> feature(const Widget& w)
{
return std::vector<bool>(10);
}
void processWidget(Widget w, bool highPriority) { /* Do something */ }
int main()
{
Widget w;
bool highPriority = feature(w)[5];
processWidget(w, highPriority);
auto highPriority2 = feature(w)[5];
// 미정의 동작
processWidget(w, highPriority2);
}
std::vector<bool> 의 operator [ ] 는 요소에 대한 참조(bool 을 제외한 모든 형식에 대해서는 std::vector::operator[ ] 가 참조를 돌려줌)가 아닌, std::vector<bool>::reference 형식의 객체를 돌려준다. 그 이유는, std::vector<bool> 이 자신의 bool 들을 bool 당 1 비트의 압축된 형태로 표현하도록 명시되어 있기 때문이다. C++ 는 비트에 대한 참조는 금지되어 있어서, std::vector<bool>::reference 를 bool 로 암묵적으로 변환하는 방식을 채택한다.
operator [ ] 가 std::vector<bool>::reference 를 반환하는데, 이는 보통 참조된 비트를 담은 기계어 워드(word) 를 가리키는 포인터 하나와 오프셋으로 구성되어 있다. 명시적으로 bool 로 선언한 경우, 해당 오프셋을 읽은 후 그 값이 바로 bool 타입으로 변환되어 저장된다. 그런데 auto 는 지금 포인터와 오프셋을 담은 객체로 연역된 상태이다. 추가로 bool 로 암시적 변환이 되는 게 아니란 뜻이다.
그런데 feature 함수는 std::vector<bool> 타입의 임시 객체(temp 라고 부르겠다)를 돌려준다. 그런데 temp 는 임시 객체이므로 문장의 끝에서 파괴된다. 따라서 highPriority 의 포인터는 대상을 잃은 포인터(dangling pointer) 가 되어 processWidget(w, highPriority2) 는 미정의 동작을 보이는 것이다.
std::vector<bool>::reference 는 대리자 클래스(proxy class), 즉 다른 어떤 형식의 행동을 흉내 내고 보강하는 것이 존재 이유인 클래스의 예이다. 그리고 대체로 이러한 "보이지 않는" 대리자 클래스는 auto 와 잘 맞지 않는 경향이 있다! 따라서, 다음과 같은 형태의 코드는 피해야 한다.
auto someVar = "보이지 않는" 대리자 클래스 형식의 표현식;
// "보이지 않는" 대리자 클래스 형식의 표현식 구현 예시
// std::vector<bool>::operator[ ] 의 명세
namespace std
{
template<class Allocator>
class vector<bool, Allocator>
{
public:
class reference { ... };
reference operator[](size_type n);
...
};
}
하지만 대리자 클래스를 쓰는 라이브러리를 사용한다고 해서 auto 를 아예 안 써야 하는 건 아니다. 다음과 같이 형식 명시 초기치 관용구(explicitly typed initializer idiom)를 사용하면 된다.
auto highPriority2 = static_cast<bool>(feature(w)[5]);
'Tutorials > C++ : Advanced' 카테고리의 다른 글
Effective Modern C++ | 항목 8 : 0 과 NULL 보다 nullptr 를 선호하라 (0) | 2022.10.26 |
---|---|
Effective Modern C++ | 항목 7 : 객체 생성 시 괄호'( )' 와 중괄호'{ }' 를 구분하라 (0) | 2022.10.26 |
Effective Modern C++ | 항목 5 : 명시적 형식 선언보다는 auto 를 선호하라 (0) | 2022.10.26 |
Effective Modern C++ | 항목 4 : 연역된 형식을 파악하는 방법을 알아두라 (0) | 2022.10.26 |
Effective Modern C++ | 항목 3 : decltype 의 작동 방식을 숙지하라 (0) | 2022.10.26 |