[Modern C++] 항목 5: 명시적 형식 선언보다는 auto를 선호하라
카테고리: Cpp
이 글은 아래의 책을 정리하였습니다. 이펙티브 모던 C++, 스콧 마이어스 저자, 류광 번역
📦 2. auto
👉🏻 항목 5: 명시적 형식 선언보다는 auto를 선호하라
1️⃣ 변수 초기화
// 명시적 형식 선언
int x1; // 문맥에 따라 초기화되지 않을 수 있음
// auto 사용
auto x2; // ⚠️ 에러! 초기치 필요!
auto x3 = 0; // ✅ x3 정의됨
auto를 사용하면, 초기화로 인한 잠재적 문제가 사라진다.
2️⃣ 변수 선언
template<typename It>
void dwim(It b, It e) {
for(; b != e; ++b) {
// 명시적 형식 선언
typename std::iterator_traits<It>::value_type
currValue = *b;
// auto 사용
auto currValue = *b;
...
}
}
- 명시적 선언의 경우, 변수 선언에 많은 수고가 든다.
3️⃣ 클로저 사용
// 명시적 형식 선언
???? derefUPLess =
[](const std::unique_ptr<Widget>& p1,
const std::unique_ptr<Widget>& p2)
{ return *p1 < *p2; };
// auto 사용: C++14 이전
auto derefUPLess =
[](const std::unique_ptr<Widget>& p1,
const std::unique_ptr<Widget>& p2)
{ return *p1 < *p2; };
// auto 사용: C++14
auto derefUPLess =
[](const auto& p1,
const auto& p2)
{ return *p1 < *p2; };
- 클로저: 람다 표현식을 통해 생성되는 익명 함수 객체
- 명시적 선언의 경우, 클로저 형식으로 변수 선언이 불가능하다.
- 클로저 형식은 컴파일러만 알고 있기 때문이다.
auto를 사용하지 않기 위해function을 사용한다 하더라도, 문제가 생긴다.
std::function<bool(const std::unique_ptr<Widget>&,
const std::unique_ptr<Widget>&)>
derefUPLess = [](const std::unique_ptr<Widget>& p1,
const std::unique_ptr<Widget>& p2)
{ return *p1 < *p2; };
메모리 사용량:
- auto:
클로저를 담는 변수 형식 = 클로저 형식이며, 필요한 만큼의 메모리만 사용한다. - function:
function 변수 형식 = function 템플릿의 인스턴스이며, 주어진 시그니처에 따라 메모리 크기가 고정되어 있다.- 메모리가 부족하면, 힙 메모리를 할당하여 사용한다.
- 메모리 부족 예외가 발생할 수도 있다.
느린 속도:
- function: 인라인화를 제한하고, 간접 함수 호출을 산출하는 구현 세부 사항이 존재한다.
- 이로 인해,
auto보다 느리다.
- 이로 인해,
4️⃣ 형식 단축
vector<int> v;
// v.size() 반환형은 vector<int>::size_type
unsigned sz = v.size();
auto sz = v.size();
v.size()의 반환형은vector<int>::size_type이며, 부호 없는 정수형이다.
문제점:
| 자료형 / 운영체제 | 32비트 Windows | 64비트 Windows |
|---|---|---|
unsigned |
32비트 | 32비트 |
vector<int>::size_type |
32비트 | 64비트 |
- 위 문제로 인해, 64비트 운영체제에서 오작동을 할 수 있다.
unordered_map<string, int> m;
// ⚠️ 비효율적임!
for(const pair<string, int>& p : m) {
...
}
// ✅
for(const auto& p : m) {
...
}
unordered_map의Key부분은const다.- 즉,
pair<const string, int>가 되어야 하며, 이로 인해 문제가 발생한다.
- 즉,
- 컴파일러는
pair<const string, int>를pair<string, int>로 변환하려 한다.p형식의 임시 객체temp생성m→temp, 각 객체 복사p→temp, 객체 묶기- 루프 끝에서,
temp파괴
- 의도치 않은 변환이 발생할 수 있다.
💡 추가 내용
- 형식 추론을 채용하는 다른 언어들이 있으며, 대규모 코드 작성 및 유지 보수에 문제가 되지 않는다.
- 객체의 형식을 파악하는 데 큰 문제가 되지 않는다.
- IDE를 통한 객체 형식 파악, 변수 이름 등을 통해 충분히 파악할 수 있다.
auto를 사용하면, 초기화 표현식이 변하더라도 코드를 수정할 일이 없다.- 즉, 리팩터링이 수월해진다. (e.g.
int→long으로 전환하는 경우)
- 즉, 리팩터링이 수월해진다. (e.g.
🧐 정리
auto변수는 반드시 초기화해야 한다.- 이식성/효율성 문제를 유발할 수 있는 형식 불일치가 발생하는 경우가 거의 없다.
- 명시적 형식 선언보다 타자량이 적어진다.
auto로 형식을 지정하면, 항목 2와 항목 6에서 설명한 문제점을 겪을 수 있다.
댓글남기기