Lyn
조회 수 6153 추천 수 0 댓글 1
Atachment
첨부 '3'
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

상당히 많은 언어가 예외 처리기를 가지고 있는데, 각각의 언어별로 특성이 있습니다.
try - catch - finally 를 모두 가지고 있는 언어(C#, Java 등) 도 있고

try - except (C 계열의 try - catch 에 대응) 와 try - finally 를 가지고 있지만 try - except 뒤에 finally 가 붙을 수 없어서 아래와 같이 중첩을 해야 하는 Pascal 계열의 언어(주로 Delphi 겠지만..) 도 있습니다


try

  try 

    //do something

  except

    //do something

finally

  //do something 


네 그리고 대망의 C++은.. finally 그런거 없습니다 (...)
C++ 표준협회에서는 stack 에 생성된 객체의 소멸자를 이용하라고 하는데 다른 언어의 코드를 C++로 옮기다가 보면 해제할것 하나하나마다 객체 만들어 주기도 보통 일이 아닙니다. 하지만 의외로 타 언어의 샘플을 C++로 옮기는게 자주 발생 하는 일이기도 하지요.


그래서 전 람다를 이용한 꼼수를 이용해서 코드를 옮길때 자주 써먹고 있습니다.
바로 아래와 같은 객체를 사용 해서요


class Finalizer
{
public:
    Finalizer()
    {

    }
    Finalizer(std::function<void(void)> fPtr)
    {
        this->fPtr = fPtr;
    }
    ~Finalizer()
    {
        if (fPtr != nullptr) fPtr();
    }
    void SetFunction(std::function<void(void)> fPtr)
    {
        this->fPtr = fPtr;
    }
private:    
    std::function<void(void)> fPtr;
};


소멸자에서 function 을 호출해 주느 매우 단순한 구조입니다.
이걸 어떻게 쓰냐면 


void test1()
{
    char* arr = new char[100];
    Finalizer final([&]
    {
        delete[] arr;
        wcout << L"Test1 : Delete Arr" << endl;
    });

    //do Something
    wcout << L"Test1 Code End" << endl;
    
    return;
}


이렇게 씁니다.

저 Finalizer 의 생성자로 lambda 를 넘겨서 finally 블록으로 삼는거죠.
그럼 포커스를 잃는순간 호출 되면서 실행 되게 됩니다.

final1.png


그럼 exception 이 발생 했을때는 어떨까요?
간단하게 아래와 같은 코드를 생각해 볼 수 있습니다


void test2()
{
    try
    {
        char* arr = new char[100];
        Finalizer final([&]
        {
            delete[] arr;
            wcout << L"Test2 : Delete Arr" << endl;
        });
        //do Something
        wcout << L"Test2 : Code End" << endl;
        
        throw L"Exception";
        
        return;        
    }
    catch (...)
    {
        wcout << L"Test2 : Exception" << endl;
    }    
}


하지만 이 코드는 문제가 하나 있는데, 코드 흐름이 다르다는겁니다

final2.png


블록을 빠져나오는것이 catch 로 넘어가는것보다 우선이기 때문에 finally 로 사용하려 했던 코드가 예외처리 코드보다 먼저 실행되어 버립니다.

이걸 해결하는건, C++은 블럭을 자유롭게 구성할 수 있다는걸 이용해서.. 바깥에 블록을 하나 더 만들어서 해결합니다




void test3()
{
    {
        Finalizer final;
        try
        {
            char* arr = new char[100];
            final.SetFunction([&]
            {
                delete[] arr;
                wcout << L"Test3 : Delete Arr" << endl;
            });
            //do Something
            wcout << L"Test3 : Code End" << endl;

            throw L"Exception";

            return;
        }
        catch (...)
        {
            wcout << L"Test3 : Exception" << endl;
        }
    }
}


위 코드는 어차피 저 코드밖에 없기 때문에 추가적인 블록이 필요 없긴 하지만... 일반적으론 그런 코드는 많지 않겠지요


final3.png


실행결과는 다음과 같습니다.
finally 블록이 다른 언어에서의 코드와 다르게 맨 뒤가 아닌 중간에 와야 하는게 맘에 들진 않는데...
대신 다른 언어에서 try 블록 내부에 선언된 변수를 finally 에서 쓸 수 없어 변수만 위쪽으로 옮기거나 하는 단점이 사라져 좋아진 것도 있습니다.


뭐 어차피 급하게 쓸때 쓰는 "꼼수" 라서요


PS. 테스트는 메모리 해제 코드로 했는데..... 메모리는 그냥 unique_ptr 이나 shared_ptr 계열 쓰세요 (...)

PS2. 더 좋은 방법 있으시면 좀 알려주세요.


아래는 전체 테스트 코드입니다

#include <iostream>
#include <functional>

using namespace std;

class Finalizer
{
public:
    Finalizer()
    {

    }
    Finalizer(std::function<void(void)> fPtr)
    {
        this->fPtr = fPtr;
    }
    ~Finalizer()
    {
        if (fPtr != nullptr) fPtr();
    }
    void SetFunction(std::function<void(void)> fPtr)
    {
        this->fPtr = fPtr;
    }
private:    
    std::function<void(void)> fPtr;
};


void test1()
{
    char* arr = new char[100];
    Finalizer final([&]
    {
        delete[] arr;
        wcout << L"Test1 : Delete Arr" << endl;
    });

    //do Something
    wcout << L"Test1 Code End" << endl;
    
    return;
}

void test2()
{
    try
    {
        char* arr = new char[100];
        Finalizer final([&]
        {
            delete[] arr;
            wcout << L"Test2 : Delete Arr" << endl;
        });
        //do Something
        wcout << L"Test2 : Code End" << endl;
        
        throw L"Exception";
        
        return;        
    }
    catch (...)
    {
        wcout << L"Test2 : Exception" << endl;
    }    
}

void test3()
{
    {
        Finalizer final;
        try
        {
            char* arr = new char[100];
            final.SetFunction([&]
            {
                delete[] arr;
                wcout << L"Test3 : Delete Arr" << endl;
            });
            //do Something
            wcout << L"Test3 : Code End" << endl;

            throw L"Exception";

            return;
        }
        catch (...)
        {
            wcout << L"Test3 : Exception" << endl;
        }
    }
}

void wmain()
{
    test1();
    wcout << endl;
    test2();
    wcout << endl;
    test3();
}
TAG •
?

List of Articles
번호 제목 글쓴이 날짜 조회 수
97 Disable Windows 10 Device Driver Automatic Update Lyn 2015.08.25 2502
96 만약 사정상 Windows 10 자동 업데이트를 꺼야 한다면 설치해야 할 패치 Lyn 2015.07.22 2514
95 잠시후 한국시각 21일 0시부터 VS 2015 런칭행사를 합니다. Lyn 2015.07.21 2403
94 VS2015 가 7월 20일 출시됩니다. Lyn 2015.06.30 2213
93 Windows 의 버전별 DPI 변경 차이 Lyn 2015.06.30 3632
92 폰트 TTF와 OTF 그 역사의 아이러니함. Lyn 2015.06.30 2967
91 Resharper C++ 사용기 - 1 file Lyn 2015.04.20 5388
90 Resharper C++ 정식버전이 떳습니다. Lyn 2015.04.11 3310
89 C++ 에서 Nuget 사용해 보기 file Lyn 2015.03.18 10978
88 MFC DLL의 InitInstance 와 ExitInstance 에서 하면 안되는 것 Lyn 2015.03.06 4471
87 오랫만에 서버 업데이트... 인데 Lyn 2015.03.03 5878
86 Android android.os.NetworkOnMainThreadException Lyn 2015.02.15 3366
85 Android Studio Gradle Error:Execution failed for task ':app:packageDebug'. > Duplicate files copied in 오류 해결 Lyn 2015.02.12 7148
» C++ 에서 타 언어의 try-finally 흉내내기 1 file Lyn 2015.01.05 6153
83 Get windows dpi setting using Direct 2D file Lyn 2015.01.05 3757
82 네... 오늘 그날입니다 그날 Lyn 2014.12.10 52450
81 VS 2013 커뮤니티 에디션이 출시되었습니다. Lyn 2014.11.13 13306
80 VS2015 Preview가 출시 되었습니다. Lyn 2014.11.13 64703
79 Windows 용 Redis 설치하기 (from nuget) file Lyn 2014.11.12 47084
78 VMWare 의 메모리 오류 해결 버전이 나왔습니다 file Lyn 2014.11.06 18696
Board Pagination Prev 1 ... 2 3 4 5 6 7 ... 8 Next
/ 8