3. 그대로 살아 있는지 어떻게 아시나요?
살아 있는 것처럼 보여도 소멸자가 죄다 불린 상태이기 때문에 (정상적으로 짜인 클래스라면) 속 빈 강정 상태가 됩니다.
정상적으로 안 짜인 클래스라면 이런 이상한 짓도 할 수 있습니다:
#include <iostream>class Base{public: ~Base(){ std::cout<<"Base class is destructing...\n";}};class Member{public: ~Member(){ std::cout<<"Member class is destructing...\n";}};class Obj:public Base { Member member;};int main(){char dummy;reinterpret_cast<Obj *>(&dummy)->~Obj();return0;}
클래스 Obj의 인스턴스는 프로그램 전체에 걸쳐 단 하나도 생성되지 않지만
그렇다 해도 아무래도 상관없는 코드이기 때문에 컴파일해서 실행시키면 동작은 합니다.
실행되는 코드가 객체가 선언된 유효범위를 벗어날 때
동적 할당된 객체에 대해 그 앞에서 delete를 언급할 때
동적할당된 객체가 아니라면, 첫 번째의 경우에 해당되 소멸자가 호출되면서, 자동으로 객체가 소멸됩니다. 두 번째 동적할당된 객체는 반드시 delete를 앞에 언급해야 하고요.
비록 소멸자가 호출된다 하더라도 객체 내부의 동적할당된 자원은 누수되지 않도록 delete로 해제해줘야 하고요.
멤버소멸이라는 개념어는 기본서에 언급된 바 없습니다. 어떤 의밀 언급하셨는지 모르나, 객체 내부의 자원(즉 동적할당된 멤버변수들)을 해제한다는 의미에서 멤버소멸이라는 단어를 선택하신 거면, 멤버소멸은 소멸자가 이행하는 것입니다. delete는 동적할당된 공간을 접으면서 소멸자를 호출하는고로 동적할당 공간정리와 멤버소멸 두 작업을 이행하게끔 하는 것이고요.
앞에서 질문자께서 작성하신 글처럼 직접 소멸자를 호출해서 객체를 소멸하는 경우는 제가 본 바가 없습니다. 가급적 동적할당된 객체는 delete를 사용해서 소멸시키는 것이 좋겠습니다.
If an implicitly-declared destructor is not deleted, it is implicitly defined (that is, a function body is generated and compiled) by the compiler when it is odr-used. This implicitly-defined destructor has an empty body.
기본 소멸자는 아무 동작도 하지 않습니다.
그리고 delete한 메모리를 접근하는 건 UB입니다..
1. 멤버 변수가 있다면 멤버 변수를 소멸시킵니다.
1. 멤버 변수가 있다면 멤버 변수를 소멸시킵니다.
2. 상속받은 클래스가 있다면 그 클래스의 소멸자가 불립니다.
3. 그대로 살아 있는지 어떻게 아시나요?
살아 있는 것처럼 보여도 소멸자가 죄다 불린 상태이기 때문에 (정상적으로 짜인 클래스라면) 속 빈 강정 상태가 됩니다.
정상적으로 안 짜인 클래스라면 이런 이상한 짓도 할 수 있습니다:
클래스 Obj의 인스턴스는 프로그램 전체에 걸쳐 단 하나도 생성되지 않지만
그렇다 해도 아무래도 상관없는 코드이기 때문에 컴파일해서 실행시키면 동작은 합니다.
물론 이런 코드 짜면 안 됩니다 ㅎㅎ.
소멸자 호출해도 멤버가 안죽어요
소멸자만 호출하면
Num에 9999가 들어와요
반면에 delete하고 보면 Num에 쓰레기값이 들어가요
이런거 보면 멤버소멸은 delete가 해주고
기본소멸자 자체로서는 아무런 동작이 없는거아닌가요?
위 답변을 뒤집으면,
위 답변을 뒤집으면,
1. 소멸시킬 멤버가 없고 2. 상속받은 클래스도 없다면 기본 소멸자는 할 일이 없습니다.
올려주신 코드의
Test
가 딱 그런 경우죠.필드가 하나 (
Member
) 있긴 한데 정수값 달랑 하나 들고 있는int
타입이잖아요.9999 대신 다른 값(쓰레기값?)이 저장되어 있으면 죽은 건가요?
delete
이후에t->Member
의 값이 변하는 이유는,delete
가 동적 할당된 메모리를 회수하기 때문입니다. 이건 구현 의존적입니다.동적 할당 메모리를 관리하기 위한 자료구조 때문인 것일 수도 있지만, 그보다는 아마 use-after-free 버그를 쉽게 확인하기 위한 디버그 기능일 가능성이 높을 거에요.
사실 제시된 코드가 바로 use-after-free를 일으키는 예시인데,
t->Member
값이 바뀐 덕분에 그 사실을 바로 알아챌 수 있죠.소멸자가 호출되는 경우 몇 가지 상황이 있습니다.
소멸자가 호출되는 경우 몇 가지 상황이 있습니다.
실행되는 코드가 객체가 선언된 유효범위를 벗어날 때
동적 할당된 객체에 대해 그 앞에서 delete를 언급할 때
동적할당된 객체가 아니라면, 첫 번째의 경우에 해당되 소멸자가 호출되면서, 자동으로 객체가 소멸됩니다. 두 번째 동적할당된 객체는 반드시 delete를 앞에 언급해야 하고요.
비록 소멸자가 호출된다 하더라도 객체 내부의 동적할당된 자원은 누수되지 않도록 delete로 해제해줘야 하고요.
멤버소멸이라는 개념어는 기본서에 언급된 바 없습니다. 어떤 의밀 언급하셨는지 모르나, 객체 내부의 자원(즉 동적할당된 멤버변수들)을 해제한다는 의미에서 멤버소멸이라는 단어를 선택하신 거면, 멤버소멸은 소멸자가 이행하는 것입니다. delete는 동적할당된 공간을 접으면서 소멸자를 호출하는고로 동적할당 공간정리와 멤버소멸 두 작업을 이행하게끔 하는 것이고요.
앞에서 질문자께서 작성하신 글처럼 직접 소멸자를 호출해서 객체를 소멸하는 경우는 제가 본 바가 없습니다. 가급적 동적할당된 객체는 delete를 사용해서 소멸시키는 것이 좋겠습니다.
eagle76fish wrote:직접 소멸자를
흔한 경우는 아닙니다만 그렇게 해야만 하는 경우가 없지는 않습니다.
객체를 위한 메모리의 할당(해제)과 객체의 생성(소멸)을 분리해야 하는 경우가 있거든요.
대표적으로
1. 메모리는 미리 잡아놓아야 하지만 아직 객체를 생성할 수는 없는 경우 (e.g.,
std::vector
)2. 객체를 위한 메모리를 뭔가 다른 방식으로 할당받아야 하는 경우
그럴 때는 1. placement new를 통해 객체를 생성하고, 소멸자를 직접 호출해서 객체를 소멸시켜야 합니다.
표준에 보면 다 나옵니다.
https://en.cppreference.com/w/cpp/language/destructor
If an implicitly-declared destructor is not deleted, it is implicitly defined (that is, a function body is generated and compiled) by the compiler when it is odr-used. This implicitly-defined destructor has an empty body.
기본 소멸자는 아무 동작도 하지 않습니다.
그리고 delete한 메모리를 접근하는 건 UB입니다..
댓글 달기