[Effective C++] 26. 변수 정의는 늦출 수 있는 데까지 늦추는 근성을 발휘하자
생성자 혹은 소멸자를 끌고 다니는 타입으로 변수를 정의하면 반드시 물게 되는 비용이 두 개 있다.
프로그램 제어 흐름이 변수의 정의에 닿을 때 생성자가 호출되는 비용, 변수가 유효 범위를 벗어날 때 소멸자가 호출되는 비용이다.
이러한 비용은 변수가 정의만 돼도 부과된다. 예제를 보자.
std::string encryptPassword(const std::string& password)
{
using namespace std;
string encrypted;
if(password.length() < MinimumPasswordLength)
{
throw logic_error("Password is too short");
}
return encrypted;
}
encrypted를 안 쓴다고 할 순 없지만, 예외가 발생되면 이 변수는 사용되지 않지만 encrypted 객체의 생성과 소멸에 대한 비용은 부과된다.
이를 해결하기 위해 encrypted의 위치를 옮겨보자.
std::string encryptPassword(const std::string& password)
{
using namespace std;
if(password.length() < MinimumPasswordLength)
{
throw logic_error("Password is too short");
}
string encrypted;
encrypted = password;
// 비밀번호 암호화
encrypt(encrypted);
return encrypted;
}
위와 같이 만들면 예외가 발생할 때는 사용하지 않게 되면서 생성자와 소멸자에 대한 자원낭비는 사라지지만 encrypted 변수가 생성될 때 기본 생성자가 호출되고, password를 대입하게 되므로 생성할 때 초기화하는 것보다 효율이 떨어진다.
즉, 아래처럼 사용하는 것이 정의와 동시에 복사 생성자를 통해 초기화 함으로써 성능을 높일 수 있고 프로그램도 깔끔해 짐을 알 수 있다.
std::string encryptPassword(const std::string& password)
{
if (password.length() < MinimumPasswordLength)
{
throw logic_error("Password is too short");
}
using namespace std;
string encrypted(password);// 정의와 동시에 초기화. 복사 생성자가 사용된다.
// 비밀번호 암호화
encrypt(encrypted);
return encrypted;
}
루프 상황에서의 변수 정의
루프 바깥쪽에 정의
Widget w;
for (int i = 0; i < n; ++i)
{
w = i에 따라 달라지는 값;
}
비용은 생성자 1번, 소멸자 1번, 대입 n번이다.
루프 안쪽에 정의
for (int i = 0; i < n; ++i)
{
Widget w(i에 따라 달라지는 값);
}
비용은 생성자 n번, 소멸자 n번이다.
결과를 보면, 일반적인 경우에는 바깥쪽에 정의하는 것보다 안쪽에 정의하는 것이 변수를 볼 수 있는 유효 범위가 좁아지기 때문에 프로그램의 이해도와 유지보수성이 증가하여 안쪽에 정의하는 것이 좋다.
하지만 대입에 들어가는 비용이 생성자-소멸자 쌍보다 적게 나오고 이러한 성능 하나하나를 민감하게 따져야 하는 경우라면 바깥쪽에 정의하는 것도 고려해볼 만하다.
요약
- 변수 정의는 늦출 수 있을 때까지 늦추자. 프로그램이 더 깔끔해지며 효율도 좋아진다.
'Books > Effective C++' 카테고리의 다른 글
[Effective C++] 28. 내부에서 사용하는 객체에 대한 '핸들'을 반환하는 코드는 되도록 피하자 (0) | 2022.06.18 |
---|---|
[Effective C++] 27. 캐스팅은 절약, 또 절약! 잊지 말자 (0) | 2022.06.18 |
[Effective C++] 25. 예외를 던지지 않는 swap에 대한 지원도 생각해 보자 (0) | 2022.06.12 |
[Effective C++] 24. 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자 (0) | 2022.06.12 |
[Effective C++] 23. 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자 (0) | 2022.06.12 |
댓글
이 글 공유하기
다른 글
-
[Effective C++] 28. 내부에서 사용하는 객체에 대한 '핸들'을 반환하는 코드는 되도록 피하자
[Effective C++] 28. 내부에서 사용하는 객체에 대한 '핸들'을 반환하는 코드는 되도록 피하자
2022.06.18 -
[Effective C++] 27. 캐스팅은 절약, 또 절약! 잊지 말자
[Effective C++] 27. 캐스팅은 절약, 또 절약! 잊지 말자
2022.06.18 -
[Effective C++] 25. 예외를 던지지 않는 swap에 대한 지원도 생각해 보자
[Effective C++] 25. 예외를 던지지 않는 swap에 대한 지원도 생각해 보자
2022.06.12 -
[Effective C++] 24. 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자
[Effective C++] 24. 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자
2022.06.12