반응형

C# .NET: Dispose (소멸자) 패턴

알게된 배경

 클래스가 프로그래밍 언어에서 등장할 때 가장 먼저 배우는 것이 생성자이다. 이후 생성자의 반대 개념인 소멸자(혹은 파괴자, 제거자 등 여러 이름으로 부를 수 있는 개념)개념이다.

 이는 기존 C++ 같은 언어에서 힙(요즘에는 이 힙을 자유공간(Free Space)라고 부르자고 제안되고 있음)에 할당된 메모리를 관리(할당과 해제)를하기 위해서였다.


 그러나 시간이 지나고 나서 GC(Garbage Collection)가 등장하고 나서 부터는 소멸자의 존재 의미가 애매 해졌다. C# DotNet Core 에서부터는 소멸자가 사라지게 되었지만, 기존의 DotNet FrameWork의 경우 아직도 소멸자가 건재하다.


 DotNet FrameWork에서는 메모리 관리 방법이 Management와 Unmanagement로 2가지 방법이 있다. Management는 말그대로 CLR이 관리를 해준다(이는 GC의 동작도 포함). 반면, Unmanagement는 CLR이 관여를 하지 않는다. 이렇게 Unmanagement한 영역은 Stream을 사용하는 부분과 소켓 프로그래밍을 위한 버퍼 등이 포함된다. 이러한 영역은 개발자가 직접 해제하는 코드를 작성해줘야 하는데, 이럴때 사용되는 것이 소멸자였다.


 그러나 DotNet FrameWork에서는 Dispose라는 인터페이스를 제공을 해주고 있는데, 이 인터페이스는 GC가 해당 Class의 인스턴스를 제거할 때 해당 작업을 먼저 하도록 되어 있다. 문제는 앞에서 언급된 Dispose 인터페이스와 소멸자의 역할이 유사하다 보니 오작동 될 가능성이 있다. 때문에 이러한 패턴이 생겨나게 되었다.


 Dispose 메서드는 IDisposeable 인터페이스를 상속 받아서 구현하면, using() 으로 호출하면 해당 스코프(혹은 스택)을 벗어나면, 호출이 된다.



패턴 예제



using System.Net.Sockets;

class UdpListenClass : IDisposeable
{
    private UdpClient Listener { get; private set; }
    // .. 중략
    // Start Destroyer Pattern
    private bool _disposed = false;
    private void Dispose(bool calledDestroyer)
    {
        if(false == _disposed)
        {
            // 소켓을 닫거나 Unmamagement 메모리를 여기서 해제하면 된다
            Listener.Close();
            _disposed = true;
        }
        if(false == calledDestroyer)
        {
            GC.SuppressFinalize(this);
        }
    }
    public void Dispose()
    {
        Dispose(false);
    }
    ~UdpSocket()
    {
        Dispose(true);
    }
    // End Destroyer Pattern
    // ... 중략
}


 혹시나 오해가 될까 추가로 적자면, 소멸자는 ~[클래스명]으로 선언 정의 된다. Dispose는 소멸자가 아니지만, using문 패턴에서 호출되는 인터패이스다. 그리고 최근에 나오고 있는 DotNet Core에서는 소멸자를 더 이상 사용하지 않는다.


 물론 DotNet FrameWork랑 독립적으로 업데이트가 되고 있지만, 새로운 기능을 2017년 8월부터 DotNet Core에 먼저 추가가 되고 이후에 DotNet FrameWork에 추가 할 것이라고 MS에서 발표를 했으니 참조만 하자


참고 자료

도서: 시작하세요. C# 6.0

도서: C# 7과 닷넷 코어 2.0

반응형

'C#' 카테고리의 다른 글

C# : using문의 기능과 활용  (0) 2018.05.15
C# .NET : SQLLocalDB (1) 개요와 오류사례  (0) 2018.03.23
C# : this와 base  (0) 2018.02.20
C# Winform : Detect Resize (크기 변화 감지)  (0) 2018.02.07
C# : Queue VS ConcurrentQueue  (0) 2018.02.02
반응형

C++ 패턴 : 동적 싱글턴(Dynamic Singleton)

정리하게 된 배경

 은근히 자주 사용되지만, 가끔 기억이 안나서 잘 못 작성한 코드의 오류를 한참 고민을 했기 때문에 후에 있을 시간을 절약하기 위해 기록을 한다.


싱글턴 패턴

 영문으로는 Singleton이라 하기 때문에 싱글톤이라 표기 한곳도 의외로 많지만, 위키백과에서는 싱글턴으로 표기를 하기 때문에 여기서는 싱글턴으로 표기를 하였다. 싱글턴 패턴도 여러 종류가 있지만, 실용적으로 자주 사용되는 동적 싱글턴 패턴에 대해서 소스코드를 적는다.


 싱글턴 패턴은 이름에서도 알 수 있 듯이 하나만 있다는 의미를 내포하고 있다. 즉, 실질적인 객체는 오직 하나이다. 싱글턴 객체를 사용하기 위해서는 싱글턴 내부에 선언되어 있는 인스턴스객체에 접근해서 사용이 가능하다. C/C++에서는 포인터의 개념을 들어 설명을 하면 이해가 쉽지만(물론 포인터를 이해했다는 전제하에) 포인터가 없는 다른 언어에서는 종종 인스턴스 참조와 인스턴스 생성간 혼란이 있는 듯하다.

 

 논리(이론)적 구성은 단하나의 객체 혹은 인스턴스가 존재해야 하며, 추가로 선언을 못하게 해야 한다. 여기서 동적 싱글톤의 경우 프로그램 시작과 관계없이 싱글턴의 인스턴스를 받아오려는 순간 생성이 되어 생성시점이 동적인 특징이 있다.


소스코드


// Singleton.hpp
#include <iostream>

class Singleton
{
private:
    Singleton(void);
    ~Singleton(void);
    static Singleton* _instance;
public:
    static Singleton* getInstance(void);
    void print(void);
};


// Singleton.cpp
#include "Singletion.hpp"

using namespace std;

Singleton* Singleton::_instance = nullptr;

Singleton* Singleton::getInstance(void)
{
    if(nullptr == _instance)
        _instance = new Singleton;
    return _instance;
}

void Singleton::print(void)
{
    cout << "singletion!" << endl;
}


// main.cpp
#include "Singleton.hpp"

Singleton* ins = Singleton::getInstance();
ins->print();
// or
Singleton::getInstance()->print();


주의할 점

 파일을 hpp에서 getInstance()를 정의할 경우에는 상관이 없지만, cpp에서 정의를 할 경우 static 키워드가 앞에 있어서는 안된다. 만약 사용한다면 문법적인 오류로 에러 메시지를 확인하게 된다.


참고자료

경험




반응형

+ Recent posts