숏컷 코드
auto count = 42; // int
auto ratio = 3.14; // double
auto name = std::string{"Mina"}; // std::string (복사)
auto& ref = name; // std::string& (참조)
const auto& view = name; // const std::string& (읽기 전용)
auto it = vec.begin(); // std::vector<int>::iterator — 긴 타입 생략auto는 타입 이름을 줄여 주지만 참조와 const를 항상 그대로 들고 오지는 않습니다. 자동 추론이 어디까지 안전한지, 어디서 명시가 필요한지 같이 봐야 합니다.
문법
먼저 다시 보는 기본형은 아래입니다.
- 단순 추론:
auto x = expr; - 참조 유지:
auto& x = expr; - 읽기 전용 참조:
const auto& x = expr; - 타입 보존:
decltype(expr)
auto의 추론 규칙 — 참조와 const는 떨어진다
auto는 오른쪽 표현식에서 타입을 추론하되, 참조와 최상위 const는 기본적으로 제거됩니다. 참조나 const를 유지하려면 auto&, const auto&처럼 직접 명시해야 합니다.
const int ci = 10;
auto a = ci; // int — const 제거됨
auto& b = ci; // const int& — 참조 추가, const 유지
const auto c = ci; // const int — const 명시
std::vector<int> v{1, 2, 3};
auto copy = v; // vector<int> 복사 (새 객체)
auto& ref = v; // vector<int>& (원본 참조)std::string name = "Mina";
auto a = name; // 복사
auto& b = name; // 참조
b += "!"; // name도 같이 바뀜같은 auto라도 & 하나 차이로 의미가 완전히 바뀝니다. "편하게 쓰는 타입 생략"이 아니라 "복사인지 참조인지 먼저 읽는 문법"으로 봐야 합니다.
auto가 빛나는 상황 — 반복자와 범위 기반 for
타입 이름이 길거나 컴파일러만 알 수 있는 경우(lambda, 반복자 등)에 auto가 코드를 크게 단순화합니다.
std::map<std::string, std::vector<int>> data;
// ❌ 타입 전체 명시
std::map<std::string, std::vector<int>>::iterator it = data.begin();
// ✅ auto로 단순화
auto it = data.begin();
// 범위 기반 for — 복사 vs 참조 선택
for (auto item : data) { ... } // pair 복사 (비용)
for (auto& item : data) { ... } // 수정 가능 참조
for (const auto& item : data) { ... } // 읽기 전용 참조 (권장)decltype — 표현식의 타입을 그대로 얻기
auto는 const/참조를 제거하는 반면, decltype은 표현식의 타입을 정확하게 그대로 반환합니다. 주로 템플릿이나 반환 타입 추론에 사용됩니다.
int x = 10;
int& r = x;
auto a = r; // int — 참조 제거
decltype(r) b = r; // int& — 참조 그대로 유지
// 함수 반환 타입 추론 (C++14)
auto add(int a, int b) -> int { return a + b; }
// decltype(auto) — 반환값 타입을 정확히 전달
decltype(auto) get_ref(std::vector<int>& v, int i) {
return v[i]; // int& — 참조 유지
}체크포인트
- 긴 타입 이름 생략:
auto - 원본 참조 유지:
auto& - 복사 없이 읽기:
const auto& - 타입을 정확히 그대로 가져오기:
decltype(expr) - 반환 타입 보존:
decltype(auto)
주의할 점
auto로 컨테이너를 받으면 복사가 발생합니다. 의도치 않은 복사를 막으려면 auto& 또는 const auto&를 씁니다.
std::vector<int> big_vec(1000000, 1);
auto copy = big_vec; // ❌ 100만 원소 복사 — 의도했나?
auto& ref = big_vec; // ✅ 참조 — 복사 없음
const auto& view = big_vec; // ✅ 읽기 전용 참조
// 범위 for에서도 동일
for (auto item : big_vec) { } // ❌ int 복사 (작아서 문제 없지만 습관)
for (const auto& item : big_vec) { } // ✅ 참조
// auto로 문자열 리터럴 받으면
auto s = "hello"; // const char* — std::string 아님!
auto str = std::string{"hello"}; // ✅ std::string// ❌ initializer_list 쪽으로 추론될 수 있어 의도와 다른 타입이 된다
auto values = {1, 2, 3}; // std::initializer_list<int>
// ✅ vector가 필요하면 타입을 분명히 적는다
std::vector<int> values_ok{1, 2, 3};참고 링크
1 sources