[C++] 항목 26: 변수 정의는 늦출 수 있는 데까지 늦추는 근성을 발휘하자
카테고리: Cpp
태그: Cpp
이 글은 아래의 책을 자세히 정리한 후, 정리한 글을 GPT에게 요약을 요청하여 작성되었습니다.
이펙티브 C++ 제3판, 스콧 마이어스 저자, 곽용재 번역
📦 5. 구현
👉🏻 항목 26: 변수 정의는 늦출 수 있는 데까지 늦추는 근성을 발휘하자
변수를 정의할 때는 두 가지 비용이 발생한다.
1. 변수 정의 시점에 생성자가 호출되는 비용
2. 유효범위를 벗어날 때 소멸자가 호출되는 비용
게다가 정의만 해놓고 사용하지 않더라도 비용은 그대로 발생한다.
예제를 보며 살펴보자.
✅ 불필요한 생성 방지
string encryptPassword(const string& password) {
string encrypted;
if(password.length() < MinimumPasswordLength) {
throw logic_error("Password is too short");
}
...
return encrypted;
}
위 코드에선 encrypted
가 먼저 생성되고, 조건에 의해 예외가 발생하면 쓸모없는 객체가 만들어진다.
이번엔 다음 코드를 살펴보자:
string encryptPassword(const string& password) {
if(password.length() < MinimumPasswordLength) {
throw logic_error("Password is too short");
}
string encrypted; // 기본 생성자 호출
encrypted = password; // 대입 연산자 호출
...
return encrypted;
}
이 경우에도, 생성 후에 또 대입이 일어난다.
좀 더 낫게 작성하면 이렇게 된다:
string encryptPassword(const string& password) {
if(password.length() < MinimumPasswordLength) {
throw logic_error("Password is too short");
}
string encrypted(password); // 정의와 동시에 초기화
...
return encrypted;
}
이렇게 작성하면 불필요한 기본 생성과 대입을 피할 수 있다.
📌 장점
- 불필요한 객체 생성을 방지
- 의미가 명확해진 상태에서 변수 정의 → 코드 문서화에도 좋음
✅ 루프에서의 변수 정의
다음은 루프 안에서의 정의 방식이다:
// A 방법
Widget w;
for(int i=0; i<n; ++i) {
w = i에 따라 달라지는 값;
...
}
// B 방법
for(int i=0; i<n; ++i) {
Widget w(i에 따라 달라지는 값);
...
}
비용 비교는 아래와 같다:
방법\호출 | 생성자 | 소멸자 | 대입 |
---|---|---|---|
A 방법 | 1번 | 1번 | n번 |
B 방법 | n번 | n번 | X |
✅ A 방법
- 생성/소멸은 1번씩만 일어나고, 대입이 n번 발생
- 단점: 변수의 유효 범위가 루프 외부까지 넓어짐 → 유지보수성 저하
✅ B 방법
- 루프마다 생성/소멸이 발생
- 대입이 없고, 유효 범위가 루프 내부로 한정
🧐 언제 어떤 방법을?
A vs B는 상황에 따라 결정하면 된다.
특히 B 방법은 아래 조건이라면 유리하다:
- 대입 연산 비용이 생성자+소멸자 비용보다 크다
- 성능에 민감한 코드
🧐 정리
- 변수 정의는 늦출 수 있을 때까지 늦추자.
→ 코드가 깔끔해지고, 효율도 높아진다. - 루프 안에서도 필요하다면 범위를 좁히고 대입을 피하자.
→ 유지보수성도 좋아진다.
댓글남기기