소멸자에서 virtual 함수동작이 다르기 때문에 종료 함수를 따로 빼줘야 할까요?

karzia의 이미지


class Object
{
public:
Object();
virtual ~Object();
void Close(){OnClose();};
protected:
virtual void OnClose(){};
};

class Item: public Object
{
public:
Item();
virtual ~Item()
{
Close();
}

virtual void OnClose()
{
SendMessageToServer("Close");
}

};

void main()
{
Item * pItem = new Item();

delete pItem;

}

위와 같은 테스트 코드가 있다고 한다면,
delete 시에 Close() 함수가 Object::OnClose()를 호출하는 사태가 발생하게 됩니다.

결국 delete 전에 Close() 함수를 불러주거나 해야 하는데, 결국 destruct에서 정리하지 못하게 되기 때문에 코드가 복잡해지게 되면,
언젠가는 새는 구멍이 나오게 됩니다.

destruct에서 해결할 수 있는 방법이나 좋은 테크닉이 없을까요?

kukyakya의 이미지

생성자와 소멸자에선 가상함수를 호출하면 안됩니다. http://www.informit.com/articles/article.aspx?p=397656

가상함수를 호출하는 일반함수도 마찬가지로 생성자와 소멸자에선 사용할 수 없습니다.

어차피 모든 자식 클래스가 OnClose()를 정의하고 소멸자에서 Close()를 호출한다면 차라리 OnClose()의 내용을 destructor로 이동시키는 것이 낫지 않을까요

karzia의 이미지


해당 코드는 예일 뿐이고,

제가 작업하는 시스템에서는 Close() 에서 하는 일이 단순히 OnClose()를 부르는게 아니라 다른 로직들과 child item들에 대한 처리 로직들이 있어서,
이 close()를 이용하여 OnClosed() 가 불려야만 정상적으로 돌아가게 됩니다. ㅠ_ㅠ

결국 현재로서는 Close() API를 delete 전에 부를 수 밖에 없어서 문제가 되더군요.

karzia의 이미지

그래서 고민해봤던것이 subsrciber 객체(즉 listener) 를 달아서 처리하는 방법을 고민해봤습니다.

즉,

class IObjectListener
{
public:
virtual void OnFinalized()=0;
};

class Object
{
public:
Object(){};
virtual ~Object();
void Close(){__pListener->OnFinalized();};
void SetListener(ObjectListener * pListener){__pListener = pListener;};

private:
IObjectListener * __pListener;
};

class Item: public Object ,IObjectListener
{
public:
Item(){SetListener(this);};
virtual ~Item()
{
Close();
}

virtual void OnFinalized()
{
SendMessageToServer("Close");
}

};

void main()
{
Item * pItem = new Item();

delete pItem;

}

이런 형식도 고민 중에 있습니다.

익명 사용자의 이미지

Item객체가 destruct될 때 Object::OnClose()가 불리는 것이 아니라 Item::OnClose()가 불릴텐데요...
한번 확인해 보세요.

karzia의 이미지

네 그게 문제라서 다른 해결방법이 없나 찾아보고 있는중입니다.

결국 delete 와 Close() 를 따로 분리하는게 가장 혼란지 적은 방법인듯합니다.

사용시에는 좀 불편하겠지만요.

익명 사용자의 이미지

만일 그러하다면 단순히 non-virtual function을 구현하면 될텐데요.

karzia의 이미지

이것저것 해봤는데요.

어떤 꽁수를 부려서 delete시에 derived class의 OnClose가 불린다하더라도, 결국 derived class의 소멸자가 불린후 base class의 destruct가 불리는 시점에 OnClose가 불릴 것이기 때문에,
단순히 method만 불릴 뿐이라서 , 위의 시도 자체가 좋지 못한 case 더군요.

결론 : destruct에서 할수 있는 일은 다하자.!
위와 같은 경우가 발생하는 경우라면, 명시적인 Close() 나 Destory() 함수를 만들어서 제공하자!.

익명 사용자의 이미지

cyclic reference의 문제 같네요. 사실 상 구분되는 두 개의 역할들이, 각각의 인스턴스로 나뉘어야 할 것들이 "상속"에 의해 하나의 인스턴스에 몰려있다보니 누가 누구를 어떻게 참조하는건지가 모호하게 되어버리는 거죠.

제시하신 내용만으로 확신할 순 없지만, 추측컨대 Object와 Item은 서로 다른 Layer에 속하는 객체들 같습니다. 가령 Object는 서버와의 통신 채널을 담당하는 LowlevelChannel, Item은 그 통신 채널 위에서 동작하는 ProtocolClient라고 볼 수 있겠지요. 이렇게 서로 다른 레이어에 속하는 객체들은 서로를 참조할 순 있겠지만, 상속을 시키는 건 별로 좋은 방식이 아닌것 같습니다.

저라면 1) Object와 Item의 상속을 제거한 뒤, 2) 둘 사이의 상호 참조를 일방향 참조로 바꿀 수 있는지 시도해보겠습니다.
만약 일방향 참조로 바꿀 수 있다면 그 참조를 ownership 관계로 간주하면 그대로 자연스럽게 해결될 것이고,
만약 그렇지 않고 상호참조가 여전히 필요하다면 둘 중 어느 것이 ownership 관계이고 어느 것이 단순 참조인지를 결정한 뒤 그에 따라 소멸 관계를 처리하겠습니다.

익명 사용자의 이미지

int close(int socketdescriptor);

class LowlevelChannel {
int sd;
public:
LowlevelChannel(char *addr) { ... }
~LowlevelChannel() { close(sd); }
int write(char* data) { ... }
};

class ProtocolClient {
LowLevelChannel chan;
public:
ProtocolClient() : chan(MY_SERVER_ADDRESS) { chan.write("HELO"); }
~ProtocolClient() { chan.write("BYE"); }
}

gilgil의 이미지

constructor와 destructor에서 virtual function은 주의를 해서 사용을 하면 됩니다(호출은 됩니다).

virtual function은 constructor 및 destructor에서 호출을 하는 경우 일반 method call과 같이 불리게 됩니다(virtual call을 하지 않음).

http://www.gilgil.net/9239

댓글 달기

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