C++의 소멸자는 자동으로 작동하지 않는다.

체스맨의 이미지

C++ 의 소멸자는 자동으로 작동하는 것이 아니라, 암묵적(implicitly)으로 호출되며, 계층적 (hierarchically)으로 호출된다. 그것이 쓰레기 수집기 (GC, Garbage Collector)가 아닌 이상 자동으로 작동한다고 볼 수 없다.

마치 자동으로 작동하는 것처럼 보이는 전역 개체나 지역개체의 소멸자들은 모두, 컴파일러에 의해 개체가 해당 scope 를 벗어나는 시점에서 암묵적으로 호출된다. 만일 소멸자가 없는 언어로 동일한 루틴을 작성한다면 scope 에 의해 명확히 드러나는 소멸 시점에서 적절히 소멸자에 해당하는 함수를 호출해주면 된다.

때로는 이러한 암묵적인 생성자/소멸자 호출이 성능 문제와 연결되기도 한다.

{
        for( i=0; i<n; i++ ) {
                MyObject object;
                object.doSomething();
                // destructor for 'object' is implicitly called here
        }
}

만일 이 루틴을 해당 개체의 특성에 따라 다음과 같이 수정할 수 있다면 성능은 증가할 수 있다.

{
        MyObject object;
        for( i=0; i<n; i++ ) {
                object.doSomething();
        }
        // destructor for 'object' is implicitly called here
}

최적화 컴파일러가 MyObject 의 생성자와 소멸자를 루프 밖으로 보내도 되는지 판단할 수 있을만큼 똑똑해져있지 않다. 또한 생성자 소멸자 호출이 암묵적으로 행해지는 C++ 같은 언어는 개발자가 위와 같은 판단을 하는 것을 방해한다.

전역 개체나 지역 개체의 생성과 소멸 문제는 이 글에서 다루려는 소멸자 문제의 핵심이 아니다. new 에 의해 동적할당되는 개체를 소멸시키기 위해서는 분명히 어느 시점에서 개발자가 delete 를 호출해주어야 한다. 이것은 delete 가 없는 언어에서, 개체를 소멸시키는 함수를 만들고 그것을 적절한 시점에서 호출해야 하는 것과 다를 바 없는 상황이 된다. 만일, '소멸자가 자동으로 작동한다'라는 말이 C++ 의 언어적 특성에 대한 환상을 준다면, C++ 을 잘 못 이해할 충분한 가능성을 제공해 줄 것이다.

이 글은 언어 논쟁을 유발하려는 의도로 쓴 글이 결코 아니다. 단지, C++ 소멸자의 작동 방식을 좀 더 적절하게 묘사하는 방법에 대해 의견을 제시한 것 뿐이다. 나는 C 를 주 개발 언어로 사용하지만, C++ 도 좋아한다. 뿐만아니라 Assembly, JAVA 나 C#, 나아가 모든 프로그램 언어들을 좋아한다. 그것들은 모두 내가 원하는 목적을 얻을 수 있을 정도의 충분한 기능들을 가지고 있기 때문이다.

홈페이지 글 주소:
http://home.megapass.net/~heesc22/orion/h_cxxdel.htm

댓글

winner의 이미지

어쩔 수 없이 논쟁이 벌어질 만한 글이라고 생각합니다.
그 논쟁을 원천적으로 봉쇄하려는 듯한 문장 역시 별로 맘에 들지는 않습니다.

사실 이런 댓글을 써도 좋은지조차 의문이 들게 하는군요.

그래도 기왕 시작한 것 이어나가자면...

자동으로 작동한다가 '현명하게 최고의 방식으로 작동한다'로 이해가 된다면 분명 말씀하신 것이 맞습니다.
하지만 보통 그렇게 생각하느냐 하면 그렇지 않다고 봅니다.
특히 C++ 를 하는 사람들은 일반적으로 효율을 중시하는 특성이 있습니다.
아마도 C++ 의 구문들이 그런 현상을 만든다고 봅니다.
그렇기에 그런 오해는 많지 않을 거라는 생각이 드는군요.

자동으로 소멸자가 호출된다는 말이 delete 가 없어도 된다는 느낌을 주긴 합니다만 그 역시 과도한 우려라고 봅니다.
효율을 중시하다보니 대게 내부과정을 알려고 하는 것이 또한 C++ programmer 의 특징입니다.

음... 댓글을 쓰다보니 이런 글을 쓰신 이유가 느껴지네요.

다만 어떻게 보아도 C++ 를 폄하하는 듯한 느낌의 문체라는 것은 어쩔 수가 없네요.

이상, 최근 C++ 에 조금씩 싫증이 나고 있는 학생이었습니다.

체스맨의 이미지

소모적 논쟁은 안벌어졌으면 좋겠습니다. :-)

왜냐면 소모적인 언어 논쟁이 있던 글을 보고 생각나서 쓴 글이기 때문입니다. 일부 거기 써 있던 문장에 대한 반박이기도 합니다만, 링크를 달지 않았습니다. 그러다보면 논쟁이 되니까요. 논쟁을 봉쇄하려는 것처럼 쓴 것은 이런 면에서 이해해 주세요...

그리고 C++ 을 폄하하지 않았습니다. 폄하처럼 느껴지셨다면, 글쎄요... 저는 그렇게 의도하지는 않았구요. 최근에 ffmpeg 을 소형 기기에 포팅할 일이 있었는데, 64 비트 정수 연산때문에 C++ 연산자 기능이 아니었으면 포팅이 어려운 상황이었습니다. 그래서... C++ 도 좋아합니다. ^^

주요 골자는 "C++ 소멸자가 자동으로 작동하는 것이 아니라, 암묵적, 계층적으로 작동한다" 라는 것입니다. 그리고 모호한 '자동' 이라는 말보다는 좀 길어도 암묵적, 계층적으로 호출된다가 더 좋지 않을까 하는 일종의 제안이랄까요...

Orion Project : http://orionids.org

누구게?의 이미지

개체의 생성자와 소멸자에
생성된 개체별로 고유한 ID를 부여하고,
이 ID가 생성된 것과 소멸된 것을 로그로 남기는 디버그 코드를
부여해 놓으면 편합니다.

이런식으로 잘 지켜보면 생각한 것과 다르게 개체가 소멸되는 것을 알 수 있고,
또한 어느시점에 delete로 명시적으로 소멸시키는 것이 바람직한지
명확히 알 수 있습니다.

전체 설계의 추상화가 잘되면 잘 될수록 생성되는 개체도 늘어나게 되고,
메모리도 많이 사용하게 됩니다.
프로그래머가 챙겨서 명시적으로 소멸시켜주지 않는
암묵적인 개체소멸만으로는 나중에는 큰 성능차이가 발생할 수도 있습니다.

only2sea의 이미지

저는 자바에 대해서 잘 모릅니다. 그런데 위에 나온 예제 코드가 과연 그것과 관련이 있는 것인지 잘 모르겠네요. 말씀하신대로라면 GC가 동작하는 자바 같은 언어에서는 다음과 같은 코드를

{
        for( i=0; i&lt;n; i++ ) {
                MyObject object = new MyObject(..);
                object.doSomething();
        }
}

아래와 같은 코드로 작성해도 괜찮은지를

{
        MyObject object = new MyObject(..);
        for( i=0; i&lt;n; i++ ) {
                object.doSomething();
        }
}

컴파일러가 결정할 수 있다는 건가요?

그렇다면 다음과 같은 C++ 코드는 어떤가요?

{
        for( i=0; i&lt;n; i++ ) {
                MyObject* object = new MyObject(..);
                object->doSomething();
                delete object;
        }
}

이렇게 되면 오히려 첫 번째 자바 코드가 더 암묵적으로 보여서 "개발자가 이와 같은 판단을 하는 것을 방해하게 되네요."(하신 말씀 그대로 인용) 적어도 이 코드에서는 매번 루프를 돌 때마다 오브젝트를 새로 생성했다가 다시 소멸시키는 것이 눈에 보이지요.

물론 정적으로 스코프 내에서 object를 생성하는 경우에 말씀하신대로 암묵적으로 호출되어서 눈에 안 보인다고 하지만 GC가 있는 자바 언어에서는 예제로 보여주신 코드에서의 문제가 과연 해결이 되는 것인지 모르겠습니다. 그래서 저는 예제가 적절하지 않은 것 같아요.

아마록에서 가사와 앨범 표지를... http://kldp.net/projects/amarok-script/ 블로그: http://turtleforward.blogspot.com

체스맨의 이미지

현존하는 어떠한 컴파일러도 그와 같은 최적화는 할 수 없습니다. 만일 그게 가능하다면 그건 어떤 의도를 표현할 수 있는 인공지능 컴파일러입니다.

하지만, 저는 자바가 그것을 할 수 있다고 얘기한 적은 없습니다. 이 글은 C++ 수준의 개체지향 언어와, C++ 이전의 비 개체 지향 언어에 대해 다루고 있다고 보시면 됩니다.

Orion Project : http://orionids.org

cleol의 이미지

제목을 보고 "어? 내가 모르는 사실이?" 하고 들어왔다가 낚였다는 생각이 들었습니다. 내용이야 나쁠 거 없지만 제목은 확실히 잘못 붙이셨습니다. "C++ 생성자는 자동으로 호출되지 않는다" 는 분명히 틀린 말입니다. 아니면 적어도 오해될 소지가 큰 문장입니다.

"C++ 소멸자는 암묵적으로 호출되며, 계층적으로 호출된다" 는 말이나 "C++ 생성자는 자동으로 호출된다" 나 포함하고 있는 정보는 거의 같습니다. "암묵적", "계층적", "자동으로" 중 어떤 단어도 객체를 힙에 생성했을 경우에 프로그래머가 소멸자를 호출해줘야한다는 뜻을 포함하지 않습니다.

그리고 이 글에는 "계층적"에 대한 내용이 없습니다.

굳이 이런 논쟁적이고 오해 소지가 큰 제목을 붙일 필요가 있을까요? 글 내용도 논쟁하려는게 아닌데 말입니다. 제목을 바꾸시는 것이 좋을 것 같습니다.

체스맨의 이미지

제가 낚았는지도 모르겠군요.:-)

'자동으로'라는 말이 말씀하신 것 만큼 결코 구체적이고 명확한 의미를 갖지 않습니다. 실제로 그 어구에 의해 두리뭉실 토론의 의견을 제시하는 경우가 있었거든요.

계층적이라는 내용은 없습니다만, 이글은 짧습니다. 저 코드 예제를 빼버리면 대여섯줄 정도의 글이지요. 예제는 사실 별로 중요한 내용이 아닌데 넣었습니다.

계층적이라는 것은 C++ 소멸자가 클래스 계승 구조 (hierarchy)에 따라 암묵적으로 호출된다는 것을 의미했습니다.

제목은 글쎄요... 낚으려는 것은 아니었지만, 그럼

'C++ 소멸자는 반자동이다.'

이렇게 하나 마찬가지 아닌지요.

Orion Project : http://orionids.org

cleol의 이미지

말씀하신데로 "자동으로"라는 말이 명확한 의미가 없으니 제목을 바꾸라는 제안입니다. ^^ 게다가 "자동적으로" 라는 단어 대신에 제안하신 "암묵적으로" 역시 "자동적으로" 보다 명확하지 않습니다.

체스맨의 이미지

제목은 느끼신대로 약간 자극적으로 쓴 경향이 있긴 합니다.
하지만 굳이 바꿀 생각은 없구요..

제 생각에는 '암묵적'이 C++ 소멸자 작동 방식을 설명할 수 있는 좋은 단어 중 하나가 아닌가 합니다. 그리고 이 말을 저만 쓰는 게 아니고 C++ 소멸자 설명할 때 나오는 말이니까요. 책에서 '자동'이라는 말과 '암묵'이라는 말이 소멸자 설명할 때 같이 쓰이는 것 같습니다.

말씀하셨듯이 C++ 개발자라면 제가 쓴 내용은 모두 기본적으로 알고 있을 것입니다. 하지만, '자동'이라는 말이 C++ 개발자의 의견에서 왜곡되는 것은, 그 단어 자체의 문제가 아닌가라는 생각을 하게 된 것입니다.

Orion Project : http://orionids.org

익명사용자의 이미지

자바라고 해도 루프 돌때마다 객체를 생성하는건 위험해 보이는데요?
자바는 첫번째 예제와 같은 경우에도 최적화를 통해 한번만 객체를 생성하나요?

kalstein의 이미지

예시로 드신 루프문은...경우에 따라 가지가지라서 어떻게 봐야할지 좀 애매하군요.

만약 소멸자의 내용이 아무것도 없는 함수이고 (MyObject::~MyObject() {}) inline으로 되어있다면 (보통 저럴경우 클래스 선언문(declare)에 소멸자 구현(implement)도 같이 해둠으로써 inline이 되는 경우가 대다수입니다) 소멸자에 대한 overhead는 신경쓰지 않아도 됩니다.

C++의 C언어 대비 가장 큰 장점으로는 역시 OOP를 지원함으로써, 시스템적으로써 사용자가 잘못할 수 있는 부분을 대다수 막고, 재사용성을 높일 수 있다는 측면이라고 볼 수 있겠는데요...MyObject의 위치가 루프 안쪽에 있을 경우에는 scope가 제약됨으로써 루프안에서만 object 객체가 사용됨을 명시 할 수 있죠. 루프 바깥쪽에 있을경우에는 생성자,소멸자의 overhead를 줄일 수 있지만, 예상치못한 객체의 사용이 일어날 수 있는거구요...

Effective C++에서는 위와같은경우, 생성자,소멸자의 overhead가 없는 경우에는 루프안쪽에 넣는것을 추천하고 있습니다. 그리고 제가 봤을때...MyObject::dosomething() 만 호출되고 있으므로 저 경우에는 루프안쪽에 넣는것이 overhead도 없으면서 구조적으로 튼튼한 코딩이라고 할 수 있을 것 같습니다.


------------------------------------------
Let`s Smart Move!!
http://kalstein.tistory.com/

익명사용자의 이미지

그래도 다행스러운 것은...

{
        for( i=0; i<n; i++ ) {
                MyObject *object = new MyObject();
                object.doSomething();
                delete object;
        }
}

{
        MyObject *object = new MyObject();
        for( i=0; i<n; i++ ) {
                object.doSomething();
        }
        delete object;
}

같이 코드를 적어놓고 "C++은 delete를 꼬박꼬박해줘야 하지만 Java에게는 GC가 있다. Java만세..."
수준은 아니라서 다행스럽습니다.

mandami의 이미지

Symbian을 보니,

생성자에서 생성될때마다 어떤 리스트에 추가하고, 소멸자에서는 그 리스트에서 삭제하는 식으로

현재 할당된 모든 클래스들의 목록을 두니, 제대로 소멸 안시킨거 뭐 있는지 찾기 쉽더군요.

체스맨의 이미지

논외이지만, Garbage Collector 가 없는 C 나 C++ 에서 작동하는 Garbage Collector 라이브러리도 있습니다. 제 글에서 논의된 건 C++ 자체에 대한 것이구요.

저도 심비안 개발을 해봤지만, 심비안을 아주 잘 알고 있다라고는 할 수 없어서 정확한 얘기는 될 수 없을겁니다.

심비안의 Cleanup Stack 은 생성된 개체들을 나열해두는 리스트가 아니라, 개체 들을 생성하는 과정에서 오류가 나타나는 경우 이미 new 된 개체들의 메모리 누수를 막기 위해 채택된 것으로 알고 있습니다. 생성이 끝나면 Pop 을 해버리기 때문에, 스택상에 개체 참조가 남지 않습니다.

아니면 다른 메커니즘을 지칭하신 것인가요?

아무튼 심비안처럼 소형 장치에서는 메모리가 열악해서 다중 실행시 메모리 오류가 발생할 확률이 데스크탑 운영체제보다 높기 때문에 이와 같은 조치를 한 것으로 알고 있구요...

Orion Project : http://orionids.org

mandami의 이미지

말씀하신 Cleanup Stack을 생각하고 쓴건 맞아요. 단순히 일반 C++에서 사용하기 쉬운 형태로 응용할 수 있도록 대충 말한 거구요.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.