[완료] C++ 에서 delete에 대한 궁금점

김일목의 이미지

만약 이런식의 프로그램을 만든다면

class A {
int a[10];
}

class B : public A {
int b[10];
}

A* a = new B;
delete a;

요렇게 하면 subclass의 데이터가 delete 되는 거 맞나요?

그리고 또,

int* array = new int[10];

delete array; 요거랑
delete[] array; 요거랑
차이가 뭔가요?

new 명령어를 사용하면 메모리 상에 어떤 방식으로 할당량의 길이가 저장 되는 건가요?

익명사용자의 이미지

A * a = new B; delete a;

위 경우는 A, B 의 delete 가 모두 이루어집니다.

int* array = new int[10];
 
delete array; // array 주소의 첫번째 int 공간만 delete 됩니다.
delete[] array; // array 에 할당된 배열 전체가 delete 됩니다.

굳이 왜 배열에 대한 delete 연산을 구분 시켜 정의해 두었는지는 모르겠지만요.

명확하게 쓰라고 그렇게 정의한것 같기도 하고 (그냥 new int 와 new int[]) 가 다르니 delete 도 다르게 쓰라고 ㅋㅋ..
앞부터 하나씩 지우고 쓰기도 하리라 생각했는지..

만든 사람의 생각은 잘 모르겠지만, 암튼 그렇습니다.

익명사용자의 이미지

아닙니다.
위의 경우 A 클래스의 소멸자를 virtual 로 선언해야 제대로 삭제가 됩니다.

delete 에서 배열에 대해 [] 를 쓰는 것은 꼭 그래야 하기 때문입니다.
delete 는 대상 객체에 대해 소멸자를 한번만 호출하지만
delete[] 를 쓰는 경우 배열안의 각 원소에 대해 소멸자를 호출합니다.

익명사용자의 이미지

따로 소멸자가 정의되어 있지 않기 때문에 소멸자가 실행되냐 안되냐는 다른 문제 이구요.
" class B : public A " 를 통해 정의된 B 클래스의 인스턴스를 delete 하면 A를 상속받은 결과로 만들어진 A 내 데이터내용도 소멸됩니다.

delete[] 라면 뒤에 넘이 배열이라 배열을 삭제하는 것이고, 안 쓰면 그냥 int 포인터니까 int 공간만 삭제되는거겠죠.
각 원소에 대한 소멸자가 호출되는건 아닙니다. 뭐, 말의 의미는 같으시겠지만..

소멸자는 클래스에만 해당되고, C++은 모든 타입이 클래스인게 아니라 자바랑 C# 등의 객체만 다루는 언어랑은 다르지요.

익명 사용자의 이미지

다른 문제가 아니지요. 확실히 소멸자를 정의해주지 않았기 때문에 컴파일러가 암시적으로 소멸자를 생성할 것이고 이 행동은 기본 소멸자를 지정해둔 것과 다르지 않습니다.
그렇게 되면 base 클래스에 자동적으로 virtual이 붙지 않기 때문에 위 같은 경우는 a의 인스턴스를 제거하는 것과 별반 다르지 않습니다. 만약 b에서 소멸자를 통해 해제해야 하는 자원 등이 남아있게 된다면 이는 리소스의 누수 문제를 야기시킬 수 있는 것이죠.

강도영의 이미지

클래스 내에서 동적으로 생성된 메모리가 있으면 당연히 소멸자를 생성해주어야 하지요.. 그러나 위의 예에서는 동적 생성이 없습니다.
그러므로 위의 경우는 문제가 없습니다.

익명 사용자의 이미지

정말로 문제가 없을까요?

#include <iostream>
#include <cstddef>
 
class Base_no_virt_dtor {
  int a[10];
};
 
class Derived_no_virt_dtor : public Base_no_virt_dtor {
  int b[10];
};
 
class Base_virt_dtor {
  int c[10];
public:
  virtual ~Base_virt_dtor() = default;
};
 
class Derived_virt_dtor : public Base_virt_dtor {
  int d[10];
};
 
// replaceable usual deallocation functions
// (since C++14)
void operator delete  ( void* ptr, std::size_t sz ) noexcept{
  std::cout << "delete (ptr=" << ptr << ", sz=" << sz << ");\n";
}
 
int main(void) {
  std::cout << "sizeof(Base_no_virt_dtor) = " << sizeof(Base_no_virt_dtor) << ";\n";
  std::cout << "sizeof(Derived_no_virt_dtor) = " << sizeof(Derived_no_virt_dtor) << ";\n";
  std::cout << "sizeof(Base_virt_dtor) = " << sizeof(Base_virt_dtor) << ";\n";
  std::cout << "sizeof(Derived_virt_dtor) = " << sizeof(Derived_virt_dtor) << ";\n";
 
  std::cout << std::endl;
 
  {
    Base_no_virt_dtor* baseptr_no_virt_dtor = new Derived_no_virt_dtor;
    std::cout << "baseptr_no_virt_dtor = " << baseptr_no_virt_dtor << ";\n";
    delete baseptr_no_virt_dtor;
  }
 
  std::cout << std::endl;
 
  {
    Base_virt_dtor* baseptr_virt_dtor = new Derived_virt_dtor;
    std::cout << "baseptr_virt_dtor = " << baseptr_virt_dtor << ";\n";
    delete baseptr_virt_dtor;
  }
  return 0;
}

실행 결과: https://ideone.com/R4ZtKY

클래스 B의 instance를 클래스 A에 대한 포인터로 받아서 delete를 시도한 영향은 소멸자에만 미치지 않습니다.

deallocation function에서도 그 차이가 보입니다. custom deallocation function에 전달되는 메모리 크기가 잘못되었죠. sizeof(B)가 아니라 sizeof(A)가 들어왔으니까요.

좀 오래된 질문 및 답변이라는 점을 감안하더라도, C++에서 polymorphism 기능을 사용할 기본 클래스는 가상 소멸자를 가져야 한다는 건 C++03 시절에도 중요한 원칙이었습니다.

설령 당장은 운이 좋아서 괜찮을 수 있다고 해도, 구태여 그런 위험을 무릅쓸 필요는 없습니다.

pok의 이미지

delete를 할당한 객체 메모리를 반환하는것을 의미하는것이라면 B 데이타의 크기만큼 메모리를 반환하는게 맞습니다.(그러니까, 자식이 A와 B의 메모리 공간을 모두 차지하게 할당이 되고 또, 그만큼 delete시에 반환합니다.)
어떻게 그렇게 되는가? 는 new에 비밀이 있는데, 좋은글이 http://kldp.org/node/1073 에 있습니다.

delete 와 delete[]은 불려지는게 다른, 완전별개의 오퍼레이터입니다.
따라서 delete aaray는 잘못된 호출방법입니다. new[]로 할당을 했으면 delete[]를 호출해서 메모리를 반환 해주어야 합니다. 관련된 내용은 MEC++에 잘 나와있습니다.


poklog at http://poksion.cafe24.com/poklog/

김일목의 이미지

많은 도움이 되었습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.