2016. 8. 14. 21:02ㆍ프로그래밍/Effective Modern C++
요약
auto를 잘 활용하면 타이핑 양이 줄어든다.
형식을 직접 지정했을 때 겪게 되는 정확성 문제와 성능 문제도 방지할 수 있다.
(흠.. 하지만 명시적으로 정의 했을 때 보다 코드 리더블은 떨어지겠지..)
auto를 선호하라
반복자가 가르키는 것을 표현하기에 명시적으로 선언하기 매우 어렵다.
간단한 선언의 즐거움으로 auto를 사용한다.
C++14부터는 람다 표현식의 매개변수에도 auto를 사용할 수 있다.
1 2 3 | auto derefUPLess = [](const auto& p1, const auto& p2) { return p1 < p2; }; | cs |
이런 꼴이 가능하다는 것.
std::function
C++11 표준 라이브러리의 한 템플릿. 함수 포인터 개념을 일반화 한 것이다.
함수 포인터는 함수만 가르키지만 std::function은 호출 가능한 객체이면 그 어떤 것도 가리킬 수 있다.
앞서 derfUpLess 함수를 Widget 객체에 대해 선언 한다면
람다 함수로 만들어지는 클로저는 호출 가능한 객체이기때문에 std::function으로 만들어야 한다.
1 2 3 4 5 | std::function<bool(const std::unique_ptr<Widget>&, const std::unique_ptr<Widget>&)> derefUpLessWidget = [](const std::unique_ptr<Widget>& p1, const std::unique_ptr<Widget>& p2) { return *p1 < *p2; }; | cs |
그럼 대충 이런 꼬라지가 나오는데................. 거의 헬이다.
중요
std::function으로 선언된 변수의 형식은 std::function 템플릿의 한 인스턴스이다.
그 크기는 주어진 서명에 대해 고정으로 되어 있다.
그러므로 클로저를 저장하기에 공간이 부족할 수 있는데 이럴 때 std::function은 힙 메모리에 클로저를 저장한다.
인라이닝을 제한하고 간접 함수 호출을 산출하는 구현 세부사항 때문에 std::function이 클로저를 호출하는 것이
auto로 선언된 객체를 통해 호출하는 것보다 대체적으로 느리다.
v.size()
std::vector<int> v 의 size를 리턴하는 함수이다.(헐..)
이 함수의 반환 형식은 std::vector<int>::size_type이다.
unsigned 로 받아 일반적으로 사용하지만 미묘한 문제가 발생할 수 있다.
32Bit Windows에서 unsigend는 32Bit이며 std::vector<int>::size_type도 32Bit로 같다.
64Bit Windows에선 unsigend는 32Bit이며 std::vector<int>::size_type는 64Bit로 서로 다르다.
드물지만 오작동 할 여지가 아주 미세하게 있다.
이럴 때 auto를 사용하면 알아서 맞춰 준다는 것.
std::pair<const std::string, int>
1 2 3 4 5 | std::unordered_map<std::string, int> m; ... for (const std::pair<std::string, int>& p : m ) { ... } | cs |
이런 코드가 있을 때 실제 for문 안쪽에 std::pair<std::string>는 std::pair<const std::string, int>로 변환된다.(실제 타입이 그것이기 떄문에.)
이런 쓸데 없는 일이 생길 수 있다.
걱정거리(내가 앞에서 언급한 코드 리더블)
auto는 선택이기 때문에 필수가 아니다. 명시적 형식 선언이 유지보수가 쉽다면 그것은 그렇게 사용하면 된다.
But, 프로그래밍 세계에서 흔히 형식 추론(type inference)라고 하는데 이것을 C++이 혁신적인 성과를 내진 못했다.
경험에 따르면 다른 언어들이 이런 형식 추론 기술에 성공했고 코드 기반의 작성 유지보수에도 문제가 없었다.
auto로 객체 형식을 파악할 수 없다는 것에 걱정하는 개발자가 많지만 IDE의 기능으로 이를 완화할 수 있다.
auto를 사용하면 리펙토링이 수월해진다.
int를 돌려주는 함수가 있었는데 long으로 바꿨다면 이를 받는 부분을 모두 long으로 바꿔야 한다.
리턴 받아 쓰는 부분들을 auto로 했다면 선언만 long으로 바꾸면 된다.
기억해 둘 사항들
auto 변수는 반드시 초기화 해야 한다. 이식성 또는 효율성 문제를 유발할 수 있는 형식 불일치가 발생하는 경우가 거의 없다.
대체로 명시적으로 지정할 때보다 타자량이 적다.
'프로그래밍 > Effective Modern C++' 카테고리의 다른 글
[effective modern c++] 항목 6 : auto가 원치 않은 형식으로 연역될 때에는 명시적 형식으로 초기화하자. (0) | 2016.09.10 |
---|---|
[effective modern c++] 항목 4: 연역된 형식을 파악하는 방법을 알아두자 (2) | 2016.07.16 |
[effective modern c++] 항목 3: decltype의 작동 방식 숙지 (2) | 2016.07.16 |
[effective modern c++] 항목 2 : auto 연역 규칙 (0) | 2016.03.01 |
[effective modern C++] 항목 1 : 템플릿 형식 연역 규칙 숙지 (2) | 2016.03.01 |