string encryptPassword(const string& password)
{
using namespace std;
string encrypted;
if (password.length() < MinimumPasswordLength)
{
throw logic_error("Password is too short");
}
... // 비밀번호를 암호화해서 encrypted 변수에 대입
return encrypted;
}
encrypted
는 예외가 발생한다면 사용하지 않는 변수이다. 그러나 encryptePassword
함수가 예외를 던져도 ecrypted
객체의 생성과 소멸에 대한 비용을 내야 한다.
string encryptPassword(const string& password)
{
using namespace std;
if (password.length() < MinimumPasswordLength)
{
throw logic_error("Password is too short");
}
string encrypted;
... // 비밀번호를 암호화해서 encrypted 변수에 대입
return encrypted;
}
변수 정의를 꼭 필요하기 전까지 미루었다.
그러나 아직 해야 할 일이 남아있다. encrypted
를 생성한 후 값을 대입하는데, 이는 원하는 값으로 직접 초기화하는 것보다 비효율적이다. 항목 4
string encryptPassword(const string& password)
{
...
string encrypted; // encrypted 생성, 기본 생성자 호출
encrypted = password; // 대입
encrypt(encrypted); // 암호화
return encrypted;
}
string encryptPassword(const string& password)
{
...
string encrypted(password); // 변수 정의와 동시에 초기화, 복사 생성자 호출
encrypt(encrypted); // 암호화
return encrypted;
}
기본 생성자를 호출한 후에 대입하는 것보다 복사 생성자를 1번 호출하는 것이 효율적이다.
루프 안에서만 쓰이는 변수는 루프 바깥에 미리 정의하고 루프 안에서 대입하는 방법이 좋을까?
아니면 루프 안에서 정의하는 방법이 좋을까?
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번
어느 방법이 효율적인지는 생성자/소멸자에 들어가는 비용과 대입에 들어가는 비용의 차이에 따라 다르다.
대입에 들어가는 비용이 더 적은 클래스라면 1번이 방법이 효율적이다. (특히 n이 더 클수록)
그렇지 않다면 2번 방법이 효율적이다.
참고해야 할 것은 1번은 w
의 유효범위가 2번보다 더 크기 때문에 유지보수 면에서 더 안좋을 수 있다.
따라서 대입이 생성자/소멸자보다 비용이 덜 들고 전체 코드에서 수행 성능에 민감한 것이 아니라면 2번 방법(루프 안에서 정의)을 쓰자!
변수 정의는 늦출 수 있는 데까지 늦추자!
1. 변수를 사용하기 전까지 변수의 정의를 늦추기
=> 사용하지 않을 객체에 대한 비용을 지불할 일이 없음
2. 가능하다면 초기화 인자를 손에 넣기 전까지 정의를 늦추기
=> 불필요한 기본 생성자 호출이 없음