2017년 9월 3일 일요일

do while(false)

어떤 작업을 하다가 문제가 생겼을 때 원래대로 복원하고 리턴해야 할 경우가 있습니다.
메모리 관리가 필요한 C++에서

MyClass MemoryAllocate()
{
    ClassA a = new ClassA();
    if(a == null)
        return NULL;

    ClassB b = new ClassB();
    if(b == null)
    {
        delete a;
        return NULL;
    }

    ClassC c = new ClassC();
    if(c == null)
    {
        delete a;
        delete b;
        return NULL;
    }

    MyClass mc = new MyClass(a, b, c);
    if(mc != null)
    {
        delete a;
        delete b;
        delete c;
        return NULL;
    }
    return mc;
}

그런데 이런 식으로 한다면 메모리할당에 문제가 생겼을때 처리하는 루틴이 많이 분산되어 있네요. 에러처리하는 루틴은 한군데 모아놓는 것이 낫죠.

MyClass MemoryAllocate()
{
    ClassA a = NULL;
    ClassB b = NULL;
    ClassC c = NULL;
    MyClass mc = NULL;

    a = new ClassA();
    if(a == NULL)
        goto ErrRtn;

    b = new ClassB();
    if(b == NULL)
        goto ErrRtn;

    ClassC c = new ClassC();
    if(c == NULL)
        goto ErrRtn;

    MyClass mc = new MyClass(a, b, c);
    if(mc != NULL)
        goto ErrRtn;
    return mc;

ErrRtn:
    if(a != NULL)
        delete a;
    if(b != NULL)
        delete b;
    if(c != NULL)
        delete c;
    if(mc != NULL)
        delete mc;
    return NULL;
}

그런데 goto문을 쓴다는 것에 거부감을 느끼는 사람이 많습니다. 저 역시 goto문은 쓰지 않으려고 하고 있거든요.
이런 경우에 do while(false문을 사용하면 구조적으로 해결할 수 있습니다.


MyClass MemoryAllocate()
{
    ClassA a = NULL;
    ClassB b = NULL;
    ClassC c = NULL;
    MyClass mc = NULL;

    do
    {
        a = new ClassA();
        if(a == NULL)
            break;

        b = new ClassB();
        if(b == NULL)
            break;

        ClassC c = new ClassC();
        if(c == NULL)
            break;

        MyClass mc = new MyClass(a, b, c);
        if(mc != NULL)
            break;
        return mc;
    } while(0);

    if(a != NULL)
        delete a;
    if(b != NULL)
        delete b;
    if(c != NULL)
        delete c;
    if(mc != NULL)
        delete mc;
    return NULL;
}