일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 일반화복사생성자
- 복사함수
- Directx9
- 상수객체참조
- private상속
- c++
- 해골책
- 템플릿
- fvf
- 도우미함수
- effectivec++.
- 부분복사
- 제네릭프로그래밍
- 이른진단
- 가상기본클래스
- operator=
- 교차dll문제
- 멤버함수템플릿
- RAII
- sharedptr
- 암시적변환
- uniqueptr
- rcsp
- 스택풀림
- most vexing parse
- contextswitching
- EffectiveC++
- 암시적인터페이스
- 정점버퍼
- 게임프로그래밍
- Today
- Total
성공할 게임개발자
[Effective c++] [5. 구현] 26. 변수 정의는 늦출 수 있는 데까지 늦추는 근성을 발휘하자 본문
변수를 앞서서 정의하면 수행 성능이 떨어진다.
생성자 소멸자를 끌고 다니는 타입으로 변수를 정의하면 각각 생성할 때, 소멸할 때 호출 비용이 발생한다. 이는 정의되어 사용되지 않아도 비용이 부과된다
std::string encryptPassword(const std::string& password)
{
using namespace std;
string encrypted;
if(password.length() < MinimumPasswordLength)
{
throw logic_error("Password is too short");
}
... // 주어진 비밀번호를 암호화하여 encrypted
// 변수에 넣는 데 필요한 일들을 여기서 한다.
return 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
// 변수에 넣는 데 필요한 일들을 여기서 한다.
return encrypted;
}
객체가 생성되고 가장 먼저하는 일이 생성자에 값을 주는 일이다. 하지만 string encrypted 변수가 정의될 때 초기화 인자가 없다.
객체를 생성하고 그 후 값을 대입하는 방법은 직접 초기화하는 방법보다 효율이 좋지 않다. (항목4 : 객체를 사용하기 전에 객체를 초기화하자)
따라서 다음의 코드처럼 string encrypted를 password로 복사생성자를 통해 초기화한다. 초기화 인자를 손에 넣기 전까지 정의는 늦출 수 있는지 둘러봐야 한다.
std::string encryptPassword(const std::string& password)
{
... //길이를 점검
std::string encrypted(password); //변수를 정의함과 동시에 초기화(복생)
encrypt(encrypted);
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번
클래스 중에는 대입에 들어가는 비용이 생성, 소멸보다 적은 경우가 있는데, Widget이 그렇다면 A를 선택해야 한다. 반대면 B를 선택해야한다.
하지만 생각해볼 부분이 하나 더 있다. A방법을 쓰면 w라는 이름을 볼 수 있는 유효범위가 B방법을 쓸 때보다 넓어지기 때문에(루프를 포함하는 유효범위) 프로그램 이해도와 유지보수성이 역으로 안 좋아진다.
따라서 아래의 방법대로 한다.
대입이 생성, 소멸자 보다 비용이 덜 들고 전체 코드에서 수행성능에 민감한 부분을 건드리지 않는다면 그냥 B방법이 좋다.
중요포인트!
변수 정의는 늦출 수 있을 때까지 늦추자. 프로그램이 더 깔끔해지며 효율도 좋아진다.
'C++' 카테고리의 다른 글
[Effective c++] [5. 구현] 28. 내부에서 사용하는 객체에 대한 "핸들"을 반환하는 코드는 되도록 피하자 (0) | 2025.06.09 |
---|---|
[Effective c++] [5. 구현] 27. 캐스팅은 절약, 또 절약! 잊지말자 (0) | 2025.06.08 |
[Effective c++] 25. 예외를 던지지 않는 swap에 대한 지원도 생각해 보자 (0) | 2025.06.07 |
[Effective c++] 24. 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자 (0) | 2025.06.06 |
[Effective c++] 23. 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자 (1) | 2025.06.05 |