⭐내가 모르는 내용있음 : 생성자. ⭐ 4번 과 해결책 중요하다!

phoenixKim·2022년 2월 28일
0

4번 내용 : 내가 모르는 내용!!

스마트 포인터를 사용하는 이유 중에 하나.

스마트 포인터를 반드시 사용해야 하는 이유
: 멤버로 객체를 가지고 있다가 생성자에서 할당하는 도중에 ,
생성자에서 예외 처리 발생시, 해당 객체의 소멸자는 호출되지 못함.

또는 이러한 경우도 있다.

  • 전문가를 위한 c++ unique_ptr 내용.
void foo()
{
	obj *p = new Object;
	p->go();
	delete p; 
}
// 를 했지만, 만약 go에서 예외발생시, foo 함수는 delete를 처리하지 않는다. 예외처리 코드로 빠지거나 , 그냥 블록 나옴.

1. 상속에서의 생성자.

  1. 파생클래스의 생성자 호출시 , 기본 클래스의 생성자가 먼저 호출됨.
  2. 기반 클래스의 생성자는 암시적으로 디폴트 생성자가 호출됨.
  3. 기본 클래스의 디폴트 생성자가 없다면, 유저가 파생클래스의 이니셜라이저에서 오버로딩 생성자를 지정해야함.
  • 주의할 점이 또 있음.
    -> 기본 클래스의 디폴트 생성자가 없어서 파생 클래스에서 오류가 발생함.

  • 지금의 경우는 디폴트도 있고, 변환 생성자도 있어서 문제 없음.

  • 디폴트 없고 변환만 있어서...
    기본 클래스의 다른 생성자를 이니셜라이저에 호출해야함.

  • 호출하는 부분

파생클래스에서 기본 클래스의 생성자 호출하는 방법에 대해
컴파일러가 선처리 영역에 명시되는 기본 생성자 호출이 없으면, 디폴트 생성자를 호출해줌.
그런데, 기반 클래스에 디폴트 생성자 존재하지 않고, 인자가 있는 생성자만 있다면, 디폴트 생성자를 만들어주지 않음.


  • 기반 클래스의 생성자를 private 처리하면 error

-- 여기서는 문제 없음.

-- private하면 error
: 파생 클래스에서 기본 클래스의 생성자 진입 못하기 때문임.

-- protected로 할 경우,
-> 자신 객체는 외부에서 생성 못함.

  • 하지만, Dog 객체의 경우, 문제 없다. 하지만 업캐스팅이 될지는 모름.

  • protected 생성자의 특징
    : 자신은 객체 만들 수 없음,
    하지만, 파생 객체는 가능함.
    -> 추상적인 존재를 만들 때 사용하면 굿!
    위의 경우와 같이 Animal은 추상적인 존재임.
    //현실 세계에 동물? 이라는 존재는 없음.


2. 생성자가 호출되는 순서

  • 멤버에 다른 객체와 상속되어 있을 경우

-> Derived의 생성자의 이니셜라이저에서 기반 클래스의 생성자가 먼저 호출됨,
이에 따라 기반 클래스의 멤버들도 초기화 훑고 지나감.
-> 파생 클래스의 멤버 초기화 이후에 파생 클래스의 생성자 내부로 진입됨을 확인할 수 있음.

//멤버보다는 기반 클래스의 생성자가 먼저 생성된다는 것에 유의해야 함.

3. 상속 관계에서의 가상 함수 호출?

  • 파생 객체에서 기반 클래스 함수 접근시, 가상함수가 함수 내부에 있따면?
    -> 당연히 파생클래스의 함수가 호출됨을 확인할 수 있음.
    : base , derived 생성자 진입하면서 가상함수 포인터가 derived의 함수로 설정되기 때문임.
  • 하지만, 생성자 진입 단계에 가상함수가 있다면, 실형식의 함수가 호출되지 않음.

생성자에서는 가상함수가 동작하지 않음.
생성자 호출 순서를 생각해보면, 당연한 결과임.
부모가 먼저 생성되고, 파생이가 생성되는데? 파생클래스의 생성자에서 가상테이블이
재정의 함수를 참조해야 함.
그런데 부모 생성자에서 가상 호출한다?
파생 클래스에서의 재정의된 가상 함수 포인터 지정을 해야 하는데, 지정도 하지 못한 상태에서 호출하기 때문에 이렇게 사용하면 안됨.


4. 생성자 예외

  • 생성자의 경우 반환하는 값이 없으므로, 생성자 내부에서 문제 발생시,
    예외를 던져야 함. 그런데 생성자에서 예외 발생시, 소멸자가 호출되지 않는다.

공식!

"생성자에서 예외가 발생하면, 소멸자 호출은 되지 않는다"
는 특징이 있다.

생성자는 확실히 완료가 되어야 소멸자 호출이 가능함.

-> 위 코드를 보면, Test 생성자 내에세 예외가 발생했기 때문에, Test의 소멸자가 호출되지 않은 문제가 발생함.
동적할당된 p를 해제하지 못하는 문제가 생김.

problem

: 위의 문제를 해결하는 코드를 작성하라.

해결책!! : 어떻게 이러한 문제를 해결할 것인가?

0번째 방법 : 멤버를 객체로 사용하자.

-> 자기 자신인 Test의 소멸자는 호출되지 않음...

1번째 방법 : 스마트 포인터를 사용하자.

: 자기 자신의 소멸자는 호출하지 못하지만, 멤버인 스맡포인터는 해제되는 것을 확인할 수 있음.

  • 차라리 Test 객체도 스마트 포인터로 하면되지 않을까? 생각해서 이렇게 했는데도
    소멸자 호출 안되네..

2번째 방법 : 컴포넌트 할당을 생성자가 아닌 다른 곳에서 진행함.


-> 다른 함수 안에서 할당, 예외처리를 하므로, 소멸자가 호출되지 않는 문제는 발생하지 않음.
: 이를 2-Phase Constructor 라고 함.

profile
🔥🔥🔥

0개의 댓글