센로그
[EC++] 4. 객체를 사용하기 전에 반드시 그 객체를 초기화하자 본문
객체의 초기화가 중요한 이유는?
- 예기치 못한 상황을 방지하기 위해서.
- C++의 객체 초기화 규칙은 랜덤인가?
- 아니다. 언제 초기화가 보장되고 아닌지 명확히 정해져있다.
- 그러나 전부 기억하기에는 규칙이 너무.. 복잡하다.
- 따라서 가장 좋은 방법은, 모든 객체를 사용 전에 항상 초기화하는 것이다.
생성자 - 대입을 통한 초기화 vs 초기화 리스트
- 대입을 통한 초기화
- 기본 생성 후에 대입이 이루어진다. 따라서 멤버 변수가 두 번 초기화된다.
- 기본 생성 후, 복사 대입 연산자를 통해 복사.
- 클래스 타입의 멤버변수의 경우, 해당 클래스의 기본 생성자가 호출되어 초기화된다.
- 이후에 생성자 내부에 있는 대입 연산을 통해 덮어씌워 지는 것이다.
- 단, 내장 타입은 별도의 초기화가 없다.
- 기본 생성 후, 복사 대입 연산자를 통해 복사.
- const 멤버나 & 멤버는 대입이 불가능하므로, 대입을 통해 초기화할 수 없다.
- 기본 생성 후에 대입이 이루어진다. 따라서 멤버 변수가 두 번 초기화된다.
- 초기화 리스트
- 객체가 생성될 때 초기화 리스트를 통해 멤버 변수에 값을 할당한다.
- 기본 생성 시 복사 생성자를 통해 복사
- 클래스 타입의 멤버변수가 초기화 리스트에 있다면, 초기화 리스트에 명시된 방식으로 생성자가 호출되어 초기화된다.
- 기본 생성 시 복사 생성자를 통해 복사
- 즉, 멤버 변수들이 객체가 메모리에 할당되는 즉시 원하는 값으로 초기화된다. (한 번만 초기화)
- const 멤버나 & 멤버도 초기화리스트를 통해 초기화할 수 있다.
- 객체가 생성될 때 초기화 리스트를 통해 멤버 변수에 값을 할당한다.
기억해야할 C++ 객체 초기화 순서
- 기본 클래스는 파생 클래스보다 먼저 초기화된다.
- 클래스 데이터 멤버는 선언된 순서대로 초기화된다.
- 초기화 리스트에서 순서가 달라져도 선언 순서대로 초기화됨
- 헷갈림 방지를 위해 초기화 리스트는 선언 순서와 맞추자
비지역 정적 객체의 초기화 순서 문제
- 한 번역 단위 내에 있는 비지역 정적 객체들은 코드 작성 순서에 따라 초기화된다.
- 그러나, 별개의 번역 단위에서 정의된 비지역 정적 객체들의 초기화 순서는 '정해져 있지 않다.'
- 변역 단위란 컴파일되는 단위를 의미한다.
- 따라서, 초기화 이전에 다른 번역 단위의 비지역 정적 객체에 의해서 참조될 수 있다!
- 이런 경우, 비지역 정적 객체를 지역 정적 객체로 바꾸면 된다.
- 지역 정적 객체는 해당 함수가 처음 호출될 때 초기화되므로, 초기화 순서 문제를 피할 수 있다.
// file1.cpp
#include <iostream>
class MyClass {
public:
MyClass() {
std::cout << "MyClass constructor called" << std::endl;
}
void doSomething() const {
std::cout << "Doing something" << std::endl;
}
};
// 비지역 정적 객체 대신, 정적 객체를 반환하는 함수 사용
MyClass& getMyClassInstance() {
static MyClass instance; // 함수 내 지역 정적 객체, 첫 호출 시 초기화됨
return instance;
}
// file2.cpp
#include <iostream>
extern MyClass& getMyClassInstance();
void useMyClass() {
getMyClassInstance().doSomething(); // 초기화 순서 문제 없이 안전하게 사용 가능
}
나의 생각
+) 내장 타입 멤버변수도 초기화 리스트에 넣는 것이 좋은가?
그렇다. 성능상 이점은 없을지라도, 다음의 이점들이 있다.
- 초기화가 보장됨
- 일관성 있게 관리 가능
- const도 초기화 가능
같은 이유로, 어떤 멤버변수를 기본 생성자로 초기화하고 싶은 경우에도 초기화 리스트를 사용하도록 한다.
+) 비지역 정적 객체 vs 지역 정적 객체
정적 객체
: 생성 시점부터 프로그램이 끝날 때까지 살아있는 객체
- 비지역 정적 객체
: 프로그램 시작 시 생성되며, 프로그램 종료 시 소멸된다.- 전역 객체
- 네임스페이스에 있는 객체
- 클래스 안에서 static으로 선언된 객체
- 파일 유효 범위에서 static으로 선언된 객체
- 지역 정적 객체
: 해당 함수가 처음 호출될 때 초기화되며, 프로그램 종료 시 소멸된다.
- 함수 안에서 static으로 선언된 객체
'Effective > Effective C++' 카테고리의 다른 글
[EC++] 6. 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자 (2) | 2024.11.13 |
---|---|
[EC++] 5. C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자 (2) | 2024.11.13 |
[EC++] 3. 낌새만 보이면 const를 들이대 보자! (6) | 2024.11.13 |
[EC++] 2. #define을 쓰려거든 const, enum, inline을 떠올리자 (0) | 2024.11.12 |
[EC++] 1. C++를 언어들의 연합체로 바라보는 안목은 필수 (0) | 2024.11.12 |
Comments