프로그래밍 언어/Effective Modern C++

[Effective Modern C++] 항목 5~6 : auto

우향우@ 2024. 11. 3. 18:46

항목 5: 명시적 선언보다 auto를 선호하자.

근거

1. 긴 타입 타자치기 편함.

2. 초기값이 꼭 필요해 초기화 안 까먹음.

3. 람다같이 꼭 써야하는 경우가 있음.

4. 람다의 경우 std::function을 대신 쓸수도 있지만 메모리가 더 들수있기에 auto가 낫다.

5. std::vector::size()의 타입은 size_type인데 윈도우 비트마다 크기가 다르다. 이걸 그냥 unsigned에 담아쓰면 윈도우마다 다른 결과 나올 수 있다. auto쓰면 괜찮음.

std::vector<int> v;

unsigned sz = v.size() // 윈도우마다 다르게 작동할 수 있음.

auto sz = v.size() // good

6. map을 아래와 같이 순회하면 tmp 복사본 만들고 그걸 참조함. 성능 안좋음. 이런 실수 auto하면 안남.

std::unorder_map<std::string, int> m;

for(const std::pair<std::string, int>& p : m)
{
	...
}
//std::pair<const std::string, int>로 해야 레퍼런스만 복사됨

7. auto쓰면 타입 바로 몰라서 가독성떨어진다고 말할 수도 있음. 하지만 지금 대세인 파이썬등은 타입 안 적음. 변수명 잘쓰면 커버가능함.

 

내 생각

auto 기반이랑 명시적 선언 기반 둘다 장단점 비슷한 것 같은데 너무 auto 선호하는 글인것 같음. 파이썬 쓸 때 타입 가독성때문에 좀 헷갈렸던 경험이 많아서 7번 잘 공감안됨. 내가 파이썬에 맞는 방법론 잘 몰라서 그런 걸수도...

 

항목 6: auto가  원치 않게 연역될때는 명시적 형식의 초기치를 사용하자.

vector<bool>의 [] 연산은 특수화 처리되어 있다. bool&는 비트에 대한 레퍼런스라 허용되지 않기 때문이다. 내부적으로 컨트롤하는 비트 reference객체를 리턴한다. 이때 얘는 복사되면 안된다. 미정의 행위이다.

auto x = boolVectorReturnFunction()[1];

 

은 위험한 구문이다.

[]연산은 reference객체를 리턴하고 이를 x에 복사하는데 컴파일러 구현따라 다르지만 비트에 대한 참조를 가진 객체를 반환할 가능성이 높다. 그리고 RValue 컨테이너였기에 문장이 끝나면 해제된다. x는 reference객체인데 해제된 비트의 참조를 가르켜 문제가 된다.

 

auto는 bool타입에 대한 복사가 이루어지도록 bool이 되어야한다.

auto x = static_cast<bool>(boolVectorReturnFunction()[1]);

이게 명시적 형식의 초기치 기법이라고 한다.

 

대리자 클래스 

대리자 클래스는 reference클래스 같이 특정 타입을 대신하는, 흉내내는 클래스이다. 스마트 포인터, 표현식 템플릿등이 있다. 대리자 클래스는 대리자가 사용되는 것을 드러내는것과 아닌것이 있는데 스마트 포인터가 전자, 표현식 템플릿이 후자다. 표현식 템플릿은 표현식 내에서 특정 타입의 계산을 효율적으로 하기 위해 연산의 결과를 해당 타입을 바로 리턴하는게 아닌 대리자 클래스를 리턴하여 효율적으로 계산하고 최종적으로 해당 클래스로 자동 형변환 된다.

Matrix m = m1 + m2 + m3 + m4;

더하기 연산들의 결과는 Sum<Sum<Matrix,Matrix>,Matrix>와 같은 타입으로 중첩되어 효율적으로 계산된다.

저 결과를 auto로 받으면 대리자 클래스를 받아버려 위험하다.

static_cast<Matrix>로 표현식을 감싸자.