작성
·
638
0
부모 클래스에서 만약에 가상함수를 한 개라도 정의했으면 가상함수 테이블이 생기고
이때 부모클래스의 가상 함수 테이블을자식 클래스가 고대로 물려받고 이때 만약 그 가상 함수를 오버라이딩 하지 않았다면 가상함수 테이블에서 가르키고 있는 함수 주소 마저 같은걸로 알고 있는데요
그러면 만약 부모클래스 소멸자를 virtual을 붙였다면 부모의 v-table이나 자식의 v-table은 소멸자에 해당하는 함수의 주소를 똑같이 가리키고 있는것이고 부모 클래스의 소멸자를 virtual을 붙이지 않았다면 부모나 자식의 v-table에는 소멸자에 대한 함수정보가 없어서 자식클래스 소멸자에 접근할 수 있는 방법이 없기 때문에 메모리릭이 발생하는것인가요..? 너무 헷갈리고 제가 뭔가 오개념이 있는거 같아서 질문드립니다.
답변 2
2
그러면 만약 부모클래스 소멸자를 virtual을 붙였다면 부모의 v-table이나 자식의 v-table은 소멸자에 해당하는 함수의 주소를 똑같이 가리키고 있는것이고 부모 클래스의 소멸자를 virtual을 붙이지 않았다면 부모나 자식의 v-table에는 소멸자에 대한 함수정보가 없어서 자식클래스 소멸자에 접근할 수 있는 방법이 없기 때문에 메모리릭이 발생하는것인가요..?
-> 그건 아니구요.
부모 클래스 소멸자에 virtual이 없다고 '항상' 메모리 릭이 일어나는 것은 아닙니다.
우선 부모에 virtual 소멸자가 붙는 경우,
현재 포인터 타입이 아니라 실제 최초로 객체를 만들었을 때 무엇으로 만들었는지에 따라
소멸자가 호출된다고 이해하시면 됩니다. (소멸자 뿐 아니라 다른 가상함수도 마찬가지)
즉 객체 0번째 오프셋에 위치한 vtable 포인터가 런타임에 채워지기 때문에
위 예제에서 우리가 Archer를 GameObject*로 관리하더라도
~Archer()가 덩달이 호출되는 것을 확인할 수 있습니다.
만약 GameObject 소멸자가 virtual이 아닌데
우리가 GameObject* archer = new Archer(); 를 했다면
Archer()가 호출되지 않는 것을 확인할 수 있죠.
위 스샷 3가지 케이스에 대해 심도있게 고민해보시기 바랍니다.
그러면 추가로 알 수 있는 것이, 만약에 ~Archer() 소멸자가 반드시 호출되었어야 했다면
(ex. Archer 클래스 내부에서 관리하는 Pet*을 원래 ~Archer()에서 정리 해줘야 한다거나...)
여기서 메모리 릭이 일어날 수 있겠죠.
1
저렇게 부모타입으로 만들어놓고 자식 클래스 객체를 호출 할 때 즉 이런 상황일때
Item* item=new Weapon() 인 상황일때
(Item이 weapon의 부모 클래스 일때)
Item의 소멸자를 가상함수로 만들었으면 type이 item이라도 weapon에 객체를 쫓아가는것이고
그렇지 않으면 결국에는 Item만 쫓아가서 Item의 소멸자만 뿅 실행하고 끝나버려서 메모리릭이 발생한다고 이해하면 맞을까요??
네 그렇습니다.
Item의 소멸자만 뿅 실행하고 끝나도 딱히 문제가 없는 상황이라면,
위험하지만 당장 버그없이 지나가겠지만,
그게 아니라 뭔가 ~Weapon()에 메모리 정리 코드가 있었다면 조금씩 메모리를 갉아먹겠죠.