생성자에서 작업하기 (Doing Work in Constructors)¶
생성자에서 가상 메서드 호출을 피하고, 오류 신호를 보낼 수 없을 때 실패할 수 있는 초기화를 피하세요.
생성자 본문에서 임의의 초기화를 수행하는 것이 가능합니다.
- 클래스가 초기화되었는지 여부에 대해 걱정할 필요가 없습니다.
-
생성자 호출에 의해 완전히 초기화되는 개체는 const일 수 있으며 표준 컨테이너나 알고리즘과 함께 사용하기가 더 쉬울 수도 있습니다.
-
작업이 가상 함수를 호출하는 경우 이러한 호출은 하위 클래스 구현으로 전달되지 않습니다. 클래스가 현재 하위 클래스로 분류되지 않은 경우에도 나중에 클래스를 수정하면 이 문제가 조용히 발생하여 많은 혼란을 야기할 수 있습니다.
- 프로그램 충돌(항상 적절한 것은 아님)이나 예외 사용(금지됨)을 제외하고 생성자가 오류를 알리는 쉬운 방법은 없습니다.
- 작업이 실패하면 이제 초기화 코드가 실패한 개체가 있으므로 호출하는 것을 잊어버리기 쉬운 bool IsValid() 상태 확인 메커니즘(또는 유사한)이 필요한 비정상적인 상태일 수 있습니다.
- 생성자의 주소를 가져올 수 없으므로 생성자에서 수행되는 모든 작업은 예를 들어 다른 스레드로 쉽게 전달될 수 없습니다.
생성자는 가상 함수를 호출하면 안 됩니다. 귀하의 코드에 적합한 경우 프로그램을 종료하는 것이 적절한 오류 처리 응답일 수 있습니다. 그렇지 않으면 TotW #42 에 설명된 대로 팩토리 함수 또는 Init() 메서드를 고려하세요. 호출할 수 있는 공용 메서드에 영향을 주는 다른 상태가 없는 개체에서는 Init() 메서드를 사용하지 마세요(이 형식의 반구조화된 개체는 특히 올바르게 작업하기 어렵습니다).
이해하기 쉽게 설명하기¶
핵심: 생성자에서 "실패할 수 있는 일"과 "가상 함수 호출"을 피하라¶
생성자는 두 가지를 잘 못합니다.
- 오류 신호: 생성자는 값을 반환하지 않습니다. 따라서 초기화가 실패해도 예외(이 프로젝트에서는 금지)나 프로그램 종료 외에는 호출자에게 알릴 깔끔한 방법이 없습니다. 실패 가능한 초기화를 생성자에 넣으면 "반쯤 만들어진 객체"가 생기고, 이를 거르려고
bool IsValid()같은 확인 장치를 두게 되는데 호출을 잊기 쉽습니다. - 가상 함수 디스패치: 생성자 안에서 가상 함수를 호출하면 하위 클래스의 재정의가 호출되지 않습니다(그 시점엔 아직 하위 객체가 만들어지지 않았으므로). 지금은 하위 클래스가 없어도 나중에 생기면 조용히 잘못 동작합니다.
대안¶
- 실패할 수 있는 초기화가 필요하면 → 팩토리 함수나 별도의
Init()메서드를 쓰세요. - 단,
Init()의 성공 여부로 갈리는 "유효/무효" 외에 다른 상태가 없는 객체라면Init()패턴을 쓰지 마세요. 반쯤 초기화된 객체는 다루기 까다롭습니다. - 코드에 적절하다면 그냥 프로그램을 종료(crash)하는 것도 올바른 오류 처리일 수 있습니다.