U E D R , A S I H C RSS

More EffectiveC++/Exception

1. Exception

1.1. Item 9: Use destuctors to prevent resource leaks.

  • Item 9: μžμ›μ΄ μƒˆλŠ”κ±Έ λ§‰λŠ” νŒŒκ΄΄μžλΌ μ‚¬μš©ν•΄λΌ.

귀여븐 동물듀 ν΄λž˜μŠ€λΌ λ§Œλ“€μ–΄ 보자.

ALAλŠ” (Adorable Little Animal이닀.)
~cpp 
    class ALA{
    publid:
        virtual void processAdiption() = 0;
        ...
    };
    class Puppy: public ALA{
    publid:
        virtual void processAdiption();
        ...
    };
    class Kitten: pubic ALA{
    publid:
        virtual void processAdiption();
        ...
    };

일단 μ—¬λŸ¬λΆ„μ€ νŒŒμΌμ—μ„œ λΆ€ν„° puppy와 kitten와 ν‚€νŠΌμ˜ μ •λ³΄λΌ μ΄λ ‡κ²Œ 읽고 λ§Œλ“ λ‹€. 사싀 Item 25에 μ–ΈκΈ‰ν•  virtual constructorκ°€ μ œκ²©μ΄μ§€λ§Œ, 일단 μš°λ¦¬μ— λͺ©μ μ— λ§žλŠ” ν•¨μˆ˜λ‘œ λŒ€μ²΄ν•œλ‹€.
~cpp 
    ALA * readALA(istream& s);

λ‹€μŒκ³Ό 같은 λŠλ‚Œ(?)으둜 좜λ ₯ν•œλ‹€.
~cpp 
    void processAdoptions( istream& dataSource)
    {
        while (dataSource) {
            ALA *pa = readALA(dataSource);
            pa->processAdoption();
            delete pa;
        }
    }
pa에 ν•΄λ‹Ήν•˜λŠ” processAdoption()은 였λ₯˜μ‹œμ— exception을 λ˜μ§„λ‹€. ν•˜μ§€λ§Œ, exceptionμ‹œμ— ν•΄λ‹Ή μ½”λ“œκ°€ λ©ˆμΆ˜λ‹€λ©΄ "delete pa;"κ°€ μˆ˜ν–‰λ˜μ§€ μ•Šμ•„μ„œ κ²°κ΅­ μžμ›μ΄ μƒˆλŠ” νš¨κ³Όκ°€ μžˆκ² μ§€ κ·Έλ ‡λ‹€λ©΄ λ‹€μŒκ³Ό 같이 일단 μ˜ˆμ™Έ μ²˜λ¦¬λΌ ν•œλ‹€. λ¬Όλ‘  ν•΄λ‹Ή ν•¨μˆ˜μ—μ„œ propagateν•΄μ£Όμ–΄ ν•¨μˆ˜ μžμ²΄μ—μ„œλ„ μ˜ˆμ™ΈλΌ λ°œμƒ μ‹œν‚¨λ‹€.

~cpp 
    void processAdoptions( istream& dataSource)
    {
        while (dataSource) {
            ALA *pa = readALA(dataSource);
            try{
                pa->processAdoption();
            }
            catch ( ... ) {
                delete pa;
                throw;
            }
            delete pa;
        }
    }
방법은 μ˜¬λ°”λ₯΄λ‹€. μ˜ˆμ™Έμ‹œμ— ν•΄λ‹Ή κ°μ²΄λΌ μ§€μ›Œ λ²„λ¦¬λŠ”κ²ƒ, 그리고 이건 μš°λ¦¬κ°€ 배운 try-catch-throwλΌ μΆ©μ‹€νžˆ μ‚¬μš©ν•œ 것이닀. ν•˜μ§€λ§Œ.. λ³΅μž‘ν•˜μ§€ μ•Šμ€κ°€? ν•΄λ‹Ή μ½”λ“œλŠ” λ§κ·ΈλŒ€λ‘œ νŽΌμ³μ§„λ‹€.(μ˜μ„œμ˜ ν‘œν˜„) 그리고 μ½”λ“œμ˜ 가독성도 떨어지며, μ°¨ν›„ 관리 μ°¨μ›μ—μ„œ μΆ”κ°€ μ½”λ“œμ˜ λ°œμƒμ‹œμ—λ„ μ–΄λŠ μ˜μ—­μ— 보강할것 인가에 κ΄€ν•˜μ—¬ λ¬Έμ œμ‹œ λœλ‹€.

μ—¬κΈ°μ—μ„œ 재λΈμžˆλŠ” 기법을 이야기 ν•΄λ³Έλ‹€. μ°¨μ°¨ μ†Œκ°œλ  smart pointer와 λ”λΆˆμ–΄ Standard C++ λΌμ΄λΈŒλŸ¬λ¦¬μ— ν¬ν•¨λ˜μ–΄ μžˆλŠ” auto_ptr template ν΄λž˜μŠ€λΌ μ΄μš©ν•œ 해결책인데 auto_prt은 μ΄λ ‡κ²Œ 생겼닀.

~cpp 
    template<class T>
    class auto_ptr{
    public:
        auto_ptr(T *p = 0) : ptr(p) {}
    private:
        T *ptr;
    };

그리고 ν•΄λ‹Ή auto_prt의 μ μš©ν•œ λͺ¨μŠ΅μ€ λ‹€μŒκ³Ό 같이 보인닀.
~cpp 
    void processAdoptions(istream& dataSource)
    {
        while (dataSource){
            auto_ptr<ALA> pa(readALA(dataSource));
            pa->processAdoption();
        }
    }

μ˜ˆμ™Έ λ°œμƒμ‹œμ— ν•¨μˆ˜κ°€ μ’…λ£Œλ˜λ©΄ auto_ptrμƒμ˜ κ°μ²΄λŠ” 무쑰건 ν•΄μ œλœλ‹€.

자자 λ‹€μŒ μ½”λ“œλ„ μžμ›μ΄ 셀것이닀.
~cpp 
    void displayIntoInfo(const Information& info)
    {
        WINDOW_HANDLE w(createWindow());
        display info in window corresponding to w;
        destroyWindow(w);
    }

일반적으둜 C의 κ°œλ…μœΌλ‘œ μ§œμ—¬μ§„ ν”„λ‘œκ·Έλž¨λ“€μ€ createWindow and destroyWindow와 같이 κ΄€λ¦¬ν•œλ‹€. κ·Έλ ‡μ§€λ§Œ 이것 μ—­μ‹œ destroyWindow(w)에 도달전에 μ˜ˆμ™Έ λ°œμƒμ‹œ μžμ›μ΄ μ„ΈλŠ” κ²½μš°κ°€ 생긴닀. κ·Έλ ‡λ‹€λ©΄ λ‹€μŒκ³Ό 같이 λ°”κΎΈμ–΄μ„œ ν•΄λ³Έλ‹€.

~cpp 
    class WidnowHandle{
    public:
        WindowHandle(WINDOW_HANDLE handle) : w(handle) {}
        ~WindowHandle() {destroyWindow(w); }
        
        operator WINDOW_HANDLE() {return w;}
    private:
        WINDOW_HANDLE w;
    
        WindowHandle(const WindowHandle&);
        WindowHandle&   operator=(const WindowHandle);

auto_ptrκ³Ό 같은 원리이닀.
~cpp 
    void displayIntoInfo(const Information& info)
    {
        WINDOW_HANDLE w(createWindow());
        display info in window corresponding to w;
    }

1.2. Item 10: Prevent resource leaks in constructors.

  • Item 10: μƒμ„±μžμ—μ„œ μžμ›μ΄ μ„ΈλŠ”κ±Έ 막아라.

자 당신이 λ©€ν‹°λΈλ””μ–΄ μ£Όμ†Œλ‘μ„ λ§Œλ“ λ‹€κ³  μƒμƒν•˜κ³ , ν”„λ‘œκ·Έλž¨μ„ 짜보자 μ „ν™”λ²ˆν˜Έ, λͺ©μ†Œλ¦¬, 사진, 이름 λ”°μœ„κ°€ λ“€μ–΄κ°€μ•Ό 할것이닀. λ‹€μŒ λŒ€κ°•μ˜ κ΅¬ν˜„ μ½”λ“œλ“€μ„ 보면
~cpp 
    class Image{
    public:
        Image(const string& imageDataFileName);
    ...
    };

    class AudioClip{
    public:
        AudioClip(const string& audioDataFileName);
        ...
    }
    class PhoneNumber{ ... };

    class BookEntry{
    public:
        BookEntry(const string& name,
                  const string& address = "",
                  const string& imageFileName = "",
                  const string& audioClipFileName = "");
        ~BookEntry();

        void addPhoneNumber(const PhoneNumber& number);
    
    private:
        string the Name;
        string the Address;
        list<phoneNumber> thePhones;
        Image *theImage;
        AudioClip *theAudioClip;
    };

각각의 BookEntryλŠ” 이름과 λ”λΆˆμ–΄ λ‹€λ₯Έ ν•„λ“œλΌ κ°€μ§€κ³  있으며 κΈ°λ³Έ μƒμ„±μžλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

~cpp 
    // κΈ°λ³Έ μƒμ„±μž
    BookEntry::BookEntry(const string& name,
                         const string& address,
                         const string& imageFileName,
                         const string& audioClipFileName)
    :theName(name), theAddress(address), theImage(0), theAudioClip(0)
    {
        if (imageFileName != ""){       // 이λΈμ§€λΌ μƒμ„±ν•œλ‹€.
            theImage = new Image(imageFileName);
        }

        if (audioClipFileName != "") {  // μ†Œλ¦¬ μ •λ³΄λΌ μƒμ„±ν•œλ‹€.
            theAudioCilp = new AudioClip( audioClipFileName);
        }
    }
    BookEntry::~BookEntry()
    {
        delete theImage;
        delete theAudioClip;
    }

μƒμ„±μžλŠ” theImage와 theAudioClipλΌ null둜 μ΄ˆκΈ°ν™” μ‹œν‚¨λ‹€. C++μƒμ—μ„œ nullκ°’μ΄λž€ deleteμƒμ—μ„œμ˜ μ•ˆμ „μ„ 보μž₯ν•œλ‹€. ν•˜μ§€λ§Œ... μœ„μ˜ μ½”λ“œμ€‘μ— λ‹€μŒ μ½”λ“œμ—μ„œ new둜 μƒμ„±ν• μ‹œμ— μ˜ˆμ™Έκ°€ λ°œμƒλœλ‹€λ©΄?
~cpp 
    if (audioClipFileName != "") {
        theAudioClip = new AudioClip(audioClipFileName);
    }

자자 예λΌλ“€μ–΄μ„œ 이런 ν•¨μˆ˜μ—μ„œ μ˜ˆμ™Έ μ²˜λ¦¬λΌ ν•΄μ•Όν• κ²ƒμ΄λ‹€.
~cpp 
    void testBookEntryClass()
    {
        BookEntry b( "Addison-Wesley Publishing Company", "One Jacob Way, Reading, MA 018678");
        ...
    }

μ΄λ ‡κ²Œ try-catch-throw둜 말이닀.
~cpp 
    void testBookEntryClass()
    {
        BookEntry *pb = 0;
        try{
            pb = new BookEntry( "Addison-Wesley Publishing Company", "One Jacob Way, Reading, MA 018678");
        }
        catch ( ... ) {
            delete pb;
            throw;
        }
        delete pb;
    }

μ΄λ ‡κ²Œ 해도 μ—¬μ „νžˆ λ¬Έμ œλŠ” λ‚¨λŠ”λ‹€. 무엇이냐 ν•˜λ©΄, λ§Œμ•½ BookEntry의 μƒμ„±μžμ€‘μ—μ„œ AudioClip 객체 생성쀑에 μ˜ˆμ™ΈλΌ propagateν•˜λ©΄ λ°”λ‘œ μœ„ μ½”λ“œμ€‘ pb 포인터에 null을 λ°˜ν™˜ν•΄ 버린닀. λ°˜λ‚©λœ μ΄λ ‡κ²Œ 되면 μ΄λΈ μ •μƒμ μœΌλ‘œ μƒμ„±λœ theImageλΌ μ§€μš°μ§€ λͺ»ν•˜λŠ” μ‚¬νƒœκ°€ λ°œμƒν•΄ λ²„λ¦¬λŠ” 것이닀.

κ·Έλ ‡λ‹€λ©΄ μƒμ„±μžμ˜ λ‚΄λΆ€μ—μ„œ λ‹€μ‹œ try-catch-throw둜 ν•΄μ•Ό 할것이닀.

~cpp 
    BookEntry::BookEntry(const string& name,
                         const string& address,
                         const string& imageFileName,
                         const string& audioClipFileName)
    :theName(name), theAddress(address), theImage(0), theAudioClip(0)
    {
        try{
            if (imageFileName != ""){
                theImage = new Image(imageFileName);
            }

            if (audioClipFileName != "") {
                theAudioCilp = new AudioClip( audioClipFileName);
            }
        }
        catch (...){
            delete theImage;
            delete theAudioClip;
            throw;
        }
    }

자 μ΄λ ‡κ²Œ ν•΄μ£Όλ©΄ 문제 될것이 μ—†λ‹€. 자 μ΄μƒνƒœμ— refactoring이 ν•„μš”ν•œ μ½”λ“œλ“€μ΄ 보일것이닀 ν•˜κ² λ‹€. delete뢀뢄을 ν•¨μˆ˜λ‘œ μ—­μ–΄ λ„λŠ” 것이닀.

~cpp 
    class BookEntry{
    public:
        ...
    private:
        ...
        void cleanup(); // 이것이 κ°μ²΄λΌ μ‚­μ œν•˜λŠ”κ±Έ 묢은것
    };

~cpp 
    BookEntry::BookEntry(const string& name,
                         const string& address,
                         const string& imageFileName,
                         const string& audioClipFileName)
    :theName(name), theAddress(address), theImage(0), theAudioClip(0)
    {
        try{
            ...
        }
        catch (...){
            cleanup();
            throw;
        }
    }
    BookEntry::~BookEntry{
        cleanup();
    }

자 이제 깨끗이 ν•΄κ²° 된 κ²ƒμœΌλ‘œ 보인닀. ν•˜μ§€λ§Œ μ΄λ²ˆμ—λŠ” 이런 κ²½μš°λΌ μƒμ •ν•΄ 보자

~cpp 
    class BookEntry{
    public :
        ...
    private:
        ...
        Image * const theImage;
        AudioClip * const theAudioClip;
    }

이런 const ν¬μΈν„°μ˜ κ²½μš°μ—λŠ” λ°˜λ“œμ‹œ μ΄ˆκΈ°ν™” λ¦¬μŠ€νŠΈλΌ μ΄μš©ν•˜μ—¬ μΈμžλΌ μ΄ˆκΈ°ν™” ν•΄μ£Όμ–΄μ•Ό ν•˜λŠ” κ²½μš°μ΄λ‹€.

~cpp 
    class BookEntry{
    public :
        ...
    private:
        ...
        Image * initImage(const string& imageFileName);
        AudioClip * initAudioClip(const string& theAudioClip);
    }

    BookEntry::BookEntry(const string& name,
                         const string& address,
                         const string& imageFileName,
                         const string& audioClipFileName)
    :theName(name), theAddress(address), 
     theImage(initImage(imageFileName)), theAudioClip(initAudioClip(AudioCilpFileName))
    {}
    // theImageλŠ” κ°€μž₯ 처음 μ΄ˆκΈ°ν™” λ˜μ–΄μ„œ μžμ›μ΄ μ„ΈλŠ” κ²ƒμ—λŒ€ν•œ 걱정이 μ—†λ‹€. κ·Έλž˜μ„œ ν•΄λ‹Ή μ†ŒμŠ€μ—μ„œ 
    // μ˜ˆμ™Έμ²˜λ¦¬λΌ μƒλž΅ν•˜μ˜€λ‹€.
   Image * initImage(const string& imageFileName)
    {
        if (imageFileName != "") return new Image(imageFileName);
        else return 0;
    }
    // theAudioClipλŠ” λ‘λ²ˆμ§Έλ‘œ μ΄ˆκΈ°ν™” 되기 λ•Œλ¬Έμ—, μ˜ˆμ™Έμ˜ λ°œμƒκ²½μš° μ΄λΈ ν• λ‹Ήλ˜μ–΄μ§„ theImage의 μžμ›μ„ 
    //  ν•΄μ œν•΄μ£ΌλŠ” μ˜ˆμ™Έ μ²˜λ¦¬κ°€ ν•„μš”ν•˜λ‹€. 
    AudioClip * initAudioClip(const string& theAudioClip)
    {
        try{
            if (adioClipFileName != ""){
                return new AudioClip(audioClipFileName);
            }
            else return 0;
        }
        catch ( ... ){
            delete theImage;
            throw;
        }
    }
이런 ν•΄κ²° 방법은 μ˜¬λ°”λ₯΄λ‹€ ν•˜μ§€λ§Œ, 이전에 μ–ΈκΈ‰ν•œ 것과 같이 μ†ŒμŠ€ 사후 관리와 ν˜„μž¬ μ†ŒμŠ€ μžμ²΄λ„ 많이 μ§€μ €λΆ„ν•˜λ‹€

κ·Έλž˜μ„œ 더 쒋은 방법은 Item 9μ—μ„œ μ–ΈκΈ‰ν•œ 방법을 μ‚¬μš©ν•˜λŠ” 것이닀.
~cpp 
    class BookEntry{
    pubcli:
    ...
    private:
    ...
    const auto_ptr<Image> theImage;
    const auto_ptr<AudioClip> theAudioClip;
그리고 μƒμ„±μžμ˜ μ½”λ“œλΌ μ΄λ ‡κ²Œ ν•œλ‹€.
~cpp 
    BookEntry::BookEntry(const string& name,
                         const string& address,
                         const string& imageFileName,
                         const string& audioClipFileName)
    :theName(name), theAddress(address),
     theImage(imageFileName != "" ? new Image(imageFileName) : 0),
     theAudioClip( audioClipFileName != "" ? new AudioClip(audioClipFileName):0)
      {}

μ΄λ ‡κ²Œ λ””μžμΈ ν• κ²½μš° νŒŒκ΄΄λŠ” μžλ™μœΌλ‘œ 이루어 진닀. 그러λ€λ‘œ νŒŒκ΄΄μžλŠ”
~cpp 
    BookEntry::~BookEntry()
    {}
μ΄λ ‡κ²Œ 아무것도 해주지 μ•Šμ•„λ„ 객체가 같이 파괴되고 λ¦¬μ†ŒμŠ€κ°€ μƒˆλŠ” 것을 방지 ν• μˆ˜ μžˆλ‹€.

1.3. Item 11: Prevent exception from leaving destuctors.

  • Item 11: 파괴자둜 λΆ€ν„°μ˜ μ˜ˆμ™Έ μ²˜λ¦¬λΌ λ§‰μ•„λΌ.

파괴자 ν˜ΈμΆœμ€ λ‘κ°€μ§€μ˜ κ²½μš°κ°€ μžˆλ‹€. μ²«λ²ˆμ§Έκ°€ 'normal'μƒνƒœλ‘œ 객체가 νŒŒκ΄΄λ˜μ–΄ μ§ˆλ•Œλ‘œ 그것은 보톡 λͺ…μ‹œμ μœΌλ‘œ deleteκ°€ λΆˆλ¦°λ‹€. λ‘λ²ˆμ§ΈλŠ” μ˜ˆμ™Έκ°€ μ „λ‹¬λ˜λ©΄μ„œ μŠ€νƒμ΄ ν’€λ¦΄λ•Œ μ˜ˆμ™Έ μ²˜λ¦¬μ‹œ(exception-handling) 객체가 νŒŒκ΄΄λ˜μ–΄ μ§€λŠ” κ²½μš°κ°€ μžˆλ‹€.

λ‹€μŒ μ˜ˆμ œλŠ” online 컴퓨터 μ„Έμ…˜μ„ μœ„ν•œ Session ν΄λž˜μŠ€λΌ μƒκ°ν•΄ λ³Έ 것이닀. 각 μ„Έμ…˜ 객체듀은 생성과 파되된 λ‚ μ§œλΌ κΈ°λ‘ν•΄μ•Όλ§Œ ν•œλ‹€.
~cpp 
    class Session{
    public:
        Session();
        ~Session();
        ...
    private:
        static void logCreation(Session *objAddr);
        static void logDestruction(Session *objAddr);
    };

λ‹€μŒκ³Ό 같이 νŒŒκ΄΄μžμ—μ„œ 둜그 λ°μ΄ν„°λΌ λ‚¨κΈ΄λ‹€.
~cpp 
    Session::~Session()
    {
        logDestruction(this);
    }

자 이건 괜μ°μ•„ 보인닀. ν•˜μ§€λ§Œ μ € logDestructionμƒμ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒν•œλ‹€λ©΄ μ–΄μ©Œκ²Œ 할것인가? ν•΄λ‹Ή μ†ŒμŠ€λŠ” Session의 파괴자 μ•ˆμ—μ„œλŠ” μ˜ˆμ™ΈλΌ μž‘μ§€ λͺ»ν•œλ‹€. κ·Έλž˜μ„œ ν•΄λ‹Ή νŒŒκ΄΄μžλΌ ν˜ΈμΆœν•œ μžμ—κ²Œ μ˜ˆμ™ΈλΌ λ˜μ§„(μ „λ‹¬ν•œ)λ‹€. κ·Έλ ‡μ§€λ§Œ λ‹€λ₯Έ μ—λŸ¬λ“€μ΄ λ˜μ Έμ§„ μƒν™©μ—μ„œ νŒŒκ΄΄μžκ°€ 슀슀둜 μžμ‹ μ„ λΆ€λ₯Έκ±°λΌλ©΄ ν•¨μˆ˜μ˜ μ’…λ£Œκ°€ μžλ™μœΌλ‘œ μ΄λ£¨μ–΄μ§€κΈ°λΌ μ›ν•  것이닀. 그리고 λ‹Ήμ‹ μ˜ ν”„λ‘œκ·Έλž¨μ€ 이μμ—μ„œ λ¨ΈμΆ”μ–΄ 버릴 것이닀. -해석이 μ΄μƒν•˜κ΅°, μ•”νŠΌ λ‹€λ₯Έ μ˜ˆμ™Έ μ²˜λ¦¬μ‹œμ— μ„Έμ…˜ 파괴자 λ‘œκ·Έμ‹œ μ˜ˆμ™Έκ°€ λ°œμƒν•œλ‹€λ©΄ ν”„λ‘œκ·Έλž¨μ΄ λ©ˆμΆ˜λ‹€λŠ” μ†Œλ¦¬λ‹€.

μ•„λ§ˆ λŒ€λ‹€μˆ˜μ˜ μ‚¬λžŒλ“€μ΄ 이런 μƒνƒœλ‘œ λΉ μ§€λŠ”κ±Έ μ›ν•˜μ§€ μ•Šμ„ 것이닀. Session 객체의 νŒŒκ΄΄λŠ” κΈ°λ‘λ˜μ§€ μ•Šμ„ νƒœλ‹ˆκΉŒ. 그건 μƒλ‹Ήνžˆ μ»€λ‹€λž€ λ¬Έμ œμ΄λ‹€ κ·ΈλŸ¬λ‚˜ 그것이 μ€λ” μ‹¬ν•œ λ¬Έμ œλΌ μœ λ°œν•˜λŠ”κ±΄ ν”„λ‘œκ·Έλž¨μ΄ 더 μ§„ν• μˆ˜ 없을 λ•Œ 일것이닀. κ·Έλž˜μ„œ Session의 νŒŒκ΄΄μžμ—μ„œμ˜ μ˜ˆμ™Έ 전달을 막아야 ν•œλ‹€. 방법은 ν•˜λ‚˜ try-catch둜 μž‘μ•„ λ²„λ¦¬λŠ” 것이닀.
~cpp 
    Session::~Sessioni()
    {
        try{
            logDestruction(this);
        }
        catch ( ... ){
            cerr << "ν•΄λ‹Ή μ£Όμ†Œμ—μ„œ μ„Έμ…˜ 객체의 파괴기둝이 λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."
                 << "-μ£Όμ†Œ:"
                 << this << ".\n";
    }       
ν•˜μ§€λ§Œ 이것도 μ›λž˜μ˜ μ½”λ“œλ³΄λ‹€ μ•ˆμ „ν•  것이 μ—†λ‹€. λ§Œμ•½ operator<< λΆ€λ₯Όλ•Œ exception이 λ°œμƒν•œλ‹€λ©΄ νŒŒκ΄΄μžκ°€ λ˜μ§€λŠ” exception으둜 λ‹€μ‹œ μš°λ¦¬κ°€ ν•΄κ²°ν•˜κ³ μž ν•˜λŠ” μ›μ μœΌλ‘œ λŒμ•„κ°€ 버린닀. κ·Έλ ‡λ‹€λ©΄
~cpp 
    Session::~Sessioni()
    {
        try{
            logDestruction(this);
        }
        catch ( ... ){ }       
μ΄λ ‡κ²Œ μ•„λ¬΄λŸ° μ²˜λ¦¬λΌ ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ logDestuctionμ—μ„œ λ°œμƒν•œ μ˜ˆμ™Έκ°€ μ „λ‹¬λ˜λŠ”κ±Έ 막고 ν”„λ‘œκ·Έλž¨ μ€‘μ§€λΌ μœ„ν•˜μ—¬ μŠ€νƒμ΄ ν’€λ €λ‚˜κ°€λŠ”κ±Έ λ§‰μ„μˆ˜λŠ” μžˆμ„ 것이닀.

ν•˜μ§€λ§Œ 이런 λ‘λ²ˆμ§Έμ˜ 생각도 νŒŒκ΄΄μžμ—μ„œ λ°œμƒν•˜λŠ” λͺ¨λ“  μ—λŸ¬λΌ λ§‰μ•„ 버리고 κ·Έλƒ₯ λ„˜μ–΄κ°€ λ²„λ¦°λ‹€λŠ” 단점이 μžˆλ‹€.
λ°‘μ˜ μ½”λ“œλŠ” DB의 νŠΈλžœμ μ…˜μ„ μ΄μš©ν•΄μ„œ μ—λŸ¬λΌ μ²˜λ¦¬ν•˜λŠ” λͺ¨μŠ΅μ΄λ‹€.
~cpp 
    Session::Session()
    {
        logCreation(this);
        startTransaction();
    }
    Session::~Session()
    {
        logDestruction(this);
        endTransaction();
    }
이럴 κ²½μš°μ—λŠ” Session의 νŒŒκ΄΄μžμ—κ²Œ λ¬Έμ œλΌ μ œκ±°ν•˜λŠ” λͺ…령을 λ‹€μ‹œ λ‚΄λ¦΄μˆ˜ μžˆλ”° ν•˜μ§€λ§Œ endTransaction이 μ˜ˆμ™ΈλΌ λ°œμƒνžˆν‚¨λ‹€λ©΄ λ‹€μ‹œ try-catch문으둜 λŒμ•„ 갈수 밖에 μ—†λ‹€.

λ‚œμ œλ‹€ λ‚œμ œ

1.4. Item 12: Understand how throwing an exception differs from passing a parameter or calling a virtual function

  • Item 12: 가상 ν•¨μˆ˜ λΆ€λ₯΄κΈ°λ‚˜, 인자 μ „λ‹¬λ‘œ μ²˜λ¦¬μ™€ μ˜ˆμ™Έμ „λ‹¬μ˜ λ°©λ²•μ˜ 차이점을 μ΄ν•΄ν•˜λΌ.

λ‹€μŒμ˜ κ°€μƒν•¨μˆ˜μ˜ μ„ μ–Έκ³Ό 같이 당신은 catch κ΅¬λ¬Έμ—μ„œλ„ λΉ„μŠ·ν•˜κ²Œ μΈμžλ“€μ„ λ„£μ„μˆ˜ μžˆλ‹€.
~cpp 
    class Widget { ... };

    void f1(Widget w);
    void f2(Widget& w);
    void f3(const Widget w);
    void f4(Widget *pw);
    void f5(const Widget *pw);

    catch (Widget w) ...
    catch (Widget& w) ...
    catch (const Widget w) ...
    catch (Widget *pw) ...
    catch (const Widget *pw) ...

κ·Έλž˜μ„œ μ•„λ§ˆ ν•¨μˆ˜ν˜ΈμΆœμ—μ„œ 인자 전달과 κ³Ό μ˜ˆμ™Έκ°€ μ „λ‹¬λ˜λŠ” 것이 기본적으둜 같은것이라고 생각 할지도 λͺ¨λ₯Έλ‹€. λΆ„λͺ… λ‘˜μ€ λΉ„μŠ·ν•œ 면이 μžˆλ‹€. ν•˜μ§€λ§Œ μ€‘μš”ν•œ 차이점 μ—­μ‹œ 쑴재 ν•œλ‹€.

자, λΉ„μŠ·ν•œ 면은 언급해보면, ν•¨μˆ˜ μ˜ˆμ™Έ λͺ¨λ‘ 에 μΈμžλΌ μ „λ‹¬ν• λ•Œ μ„Έκ°€μ§€λ‘œ μ „λ‹¬ν• μˆ˜ μžˆλ‹€. κ°’(by value)이냐 μ°Έμ‘°(by reference)냐, ν˜Ήμ€ 포인터(by pointer)냐 λ°”λ‘œ 이것이닀. ν•˜μ§€λ§Œ 이 ν•¨μˆ˜μ™€ μ˜ˆμ™Έμ—μ„œμ˜ 인자의 전달 방식은 ꡬ동 λ°©λ²•μ—μ„œ 결정적인 차이점을 보인닀. 이런 차이점은 당신이 ν•¨μˆ˜λΌ ν˜ΈμΆœν• λ•Œ μ΅œμ’…μ μœΌλ‘œ λ°˜ν™˜λ˜λŠ” κ°’(returns)이 ν•΄λ‹Ή ν•¨μˆ˜λΌ λΆ€λ₯΄λŠ” μœ„μΉ˜λ‘œ κ°€μ§€λ§Œ, μ˜ˆμ™Έμ˜ κ²½μš°μ— throw의 μœ„μΉ˜μ™€ return의 μœ„μΉ˜κ°€ λ‹€λ₯΄λ‹€λŠ” μ μ—μ„œ κΈ°μΈν•œλ‹€.

λ‹€μŒ ν•¨μˆ˜μ—μ„œ Widget의 인자 전달과 μ˜ˆμ™Έμ—μ„œμ˜ 전달을 생각해 보자.
~cpp 
    // 이 μ†ŒμŠ€λŠ” μœ„μ˜ Widget의 μΌν™˜μ΄λΌκ³  μƒκ°ν•˜λ©΄ 무리 μ—†κ² λ‹€.
    istream operator>>(istream& s, Widget& w);
    void passAndThrowWidget()
    {
        Widget localWidget;
        cin >> localWidget;
        throw localWidget;
    }

localWidget이 operator>> 둜 μ „λ‹¬λ λ•ŒλŠ” λ³΅μ‚¬μ˜ 과정이 μΌμ–΄λ‚˜μ§€ μ•ŠλŠ”λ‹€. λŒ€μ‹  operator>> μ•ˆμ˜ μ°Έμ‘° wκ°€ localWidgetκ³Ό λ¬Άμ—¬μ„œ μ–΄λ– ν•œ 과정을 μ²˜λ¦¬ν•˜κ²Œ λœλ‹€. ν•˜μ§€λ§Œ μ˜ˆμ™Έμ˜ μ²˜λ¦¬μ—μ„œ localWidget은 μ€ λ‹€λ₯Έ μ΄μ•ΌκΈ°λΌ λ§Œλ“€μ–΄ λ‚˜κ°„λ‹€. μ˜ˆμ™Έκ°€ κ°’μ΄λ‚˜, μ°Έμ‘°λΌ μž‘λ“  μž‘μ§€(pointerλŠ” μž‘μ§€ λͺ»ν•œλ‹€.) μ•Šλ“  상관 없이 localWidget의 사본이 λ§Œλ“€μ–΄μ§€κ³ , κ·Έ 사본은 catch둜 μ €λ‚Ÿγ„Ή λœλ‹€. μ™œλƒν•˜λ©΄ passAndThrowWidget의 μ˜μ—­μ„ λ²—μ–΄λ‚˜λ©΄ localWidget의 파괴자의 호좜이 되기 λ•Œλ¬Έμ— λ°˜λ“œμ‹œ μ΄λ ‡κ²Œ λ˜μ–΄μ•Ό ν•œλ‹€. 이것은 C++ μ—μ„œ μ˜ˆμ™ΈλŠ” 항상 μ‚¬λ³ΈμœΌλ‘œ μ „λ‹¬λœλ‹€λŠ” μ΄μœ κ°€ λœλ‹€.

이런 λ³΅μ‚¬μ˜ 과정은 아무리 파괴의 μœ„ν—˜μ΄ μ—†λŠ” μ˜ˆμ™ΈλΌλ„ 이루어 진닀. μ˜ˆλΌ λ“€μžλ©΄

~cpp 
    void passAndThrowWidget()
    {
        static Widget localWidget;
        cin >> localWidget;
        throw localWidget;
    }

ν•΄λ‹Ή 사본은 ꡬ지 볡사할 ν•„μš”κ°€ 없을 것이닀. ν•˜μ§€λ§Œ catch λŠ” 볡사해 λ‚˜κ°€κ³  κ·Έλž˜μ•Όλ§Œ catch μ—μ„œ localWidget의 사본을 νŽΈμ§‘ν•΄μ„œ μ΄μš©ν• μˆ˜ μžˆλ‹€. μ΄λŸ¬ν•œ λ³΅μ‚¬μ˜ κ·œμΉ™μ€ ν•¨μˆ˜ 전달과 μ˜ˆμ™Έ 인자 μ „λ‹¬μ˜ 차이점을 μ„λͺ…ν•΄ μ€λ‹€.

객체가 μ˜ˆμ™ΈλΌ μœ„ν•˜μ—¬ 볡사가 λ λ•Œ λ³΅μ‚¬λŠ” ν•΄λ‹Ή 객체의 λ³΅μ‚¬μƒμ„±μž(copy constructor)에 μ˜ν•˜μ—¬ μˆ˜ν–‰ λœλ‹€. 이 λ³΅μ‚¬μƒμ„±μžλŠ” 객체의 dynamicν˜•μ΄ μ•„λ‹Œ static ν˜•μ— ν•΄λ‹Ήν•˜λŠ” ν΄λž˜μŠ€μ€‘ ν•˜λ‚˜μ΄λ‹€. κ°œλ…μ˜ 확인을 μœ„ν•΄ μœ„ μ†ŒμŠ€μ˜ μˆ˜μ • 버전을 생각해 보자
~cpp 
class Widget { ...}
class SpecialWidget: public Widget { ... };
void passAndThrowWidget()
{
    SpecialWidget localSpecialWidget;
    ...
    Widget& rw = localSpecialWidget;
    throw rw;                           // rw의 ν˜• 즉 Widget의 λ³΅μ‚¬μƒμ„±μžκ°€ μž‘λ™ν•˜μ—¬ 볡사해 μ˜ˆμ™ΈλΌ λ°œμƒμ‹œν‚¨λ‹€.
}

λ‹€μŒμ˜ 경우 passAndThrowWidget 이 λ˜μ§€λŠ”κ±΄ Widget 이닀. μœ„μ—μ„œ μ–ΈκΈ‰ν–ˆλ“이 static type으둜 μ˜ˆμ™ΈλŠ” μ „λ‹¬λœλ‹€. μ»΄νŒŒμΌλŸ¬λŠ” rwκ°€ SpecialWidget으둜의 λ™μž‘μ„ μ „ν˜€ μƒκ°ν•˜μ§€ μ•ŠλŠ”λ‹€.

μ˜ˆμ™Έμ²˜λ¦¬μ‹œμ— λ‹€λ₯Έ 객체의 사본이 전달 λœλ‹€λŠ” 점은 μ˜ˆμ™Έκ°€ 계속 전달(νΌμ Έλ‚˜κ°ˆλ•Œ,propagate)에도 ν•œκ°€μ§€μ˜ 고렀사항이 λ°œμƒν•œλ‹€. λ‹€μŒμ˜ λ‘κ°€μ§€μ˜ catch λΈ”λŸ­μ€ 차이점이 μžˆλ‹€. ν•˜μ§€λ§Œ 외견상 같은 역할을 ν•œλ‹€.
~cpp 
    catch (Widget& w)
    {
        ...
        throw;              // ν•΄λ‹Ή κ°μ²΄λΌ λ‹€μ‹œ λ³΅μ‚¬ν•˜μ§€ μ•Šκ³  λ˜μ§€λ©°, ν•΄λ‹Ή μ˜ˆμ™ΈλΌ propagete ν•œλ‹€. 
    }
    catch (Widget& w)
    {
        ...
        throw w;            // ν•΄λ‹Ή κ°μ²΄λΌ λ‹€μ‹œ λ³΅μ‚¬ν•΄μ„œ κ·Έ 사본을 propagateν•œλ‹€.
    }
주석에 λ˜μ–΄ μžˆλŠ”λ°λ‘œ, 생각해 보라. throwκ°€ λ³΅μ‚¬μƒμ„±μžλΌ ν˜ΈμΆœν•˜μ§€ μ•Šμ•„μ„œ νš¨μœ¨μ μ΄λ‹€. 그리고 throwλŠ” μ–΄λ– ν•œ ν˜•μ΄λ“  μ˜ˆμ™ΈλΌ μ „λ‹¬ν•œλŠ”λ° μƒκ΄€ν•˜μ§€ μ•ŠλŠ”λ‹€. ν•˜μ§€λ§Œ, 사싀 μ˜ˆμ™Έμžμ²΄κ°€ κ·Έ ν˜•μ— 맞게 λ˜μ Έμ§€λ€λ‘œ 걱정이 μ—†λ‹€. ν•˜μ§€λ§Œ catchλ¬Έμ—μ„œ μ˜ˆμ™ΈλΌ λ˜μ§€λŠ” 객체의 ν˜•νƒœλΌ λ°”κΏ€ ν•„μš”μ„±μ΄ μžˆμ„λ•Œ ν›„μžλΌ μ‚¬μš©ν•΄μ•Ό κ² λ‹€.

자 그럼 λ‹€μŒμ˜ 세가지 catch에 κ΄€ν•΄μ„œ μ‹œν—˜ν•΄ 보자. passAndThrowWidgetμ—μ„œ λ°œμƒν•œ μ˜ˆμ™ΈλŠ” λ‹€μŒμ˜ μ„Έκ°€μ§€μ˜ 경우둜 μž‘μ„μˆ˜ μžˆλŠ”κ±Έ μ˜ˆμƒν• μˆ˜ μžˆλ‹€.
~cpp 
catch (Widget w) ...        // κ°’μœΌλ‘œ 전달

catch (Widget& w) ...       // μ°Έμ‘° 전달

catch (const Widget& w) ... // μƒμˆ˜ 참쑰둜 전달
μ „λ‹¬λœ κ°μ²΄λŠ” κ°„λ‹¨νžˆ 참쑰둜 μž‘μ„μˆ˜ μžˆλ‹€;그것은 μƒμˆ˜ 참쑰둜 전달될 ν•„μš”μ„±μ€ μ—†λ‹€. κ·ΈλŸ¬λ‚˜ μƒμˆ˜ μ°Έμ‘°κ°€ μ•„λ‹Œ 전달 μž„μ‹œ 객체듀은 ν•¨μˆ˜λΌ λΆ€λ₯΄λŠ”κ±Έ ν—ˆμš©ν•˜μ§€ μ•ŠλŠ”λ‹€.

그럼 μ΄λ“€μ˜ 차이점을 μ‚΄νŽ΄λ³΄κ³  μ˜ˆμ™Έ 객체듀을 리턴해 보자.

~cpp 
    catch (Widget w) ...    // κ°’μœΌλ‘œ 전달
μ΄λ ‡κ²Œ κ°’μœΌλ‘œ μ „λ‹¬ν•˜λ©΄ λ‘λ²ˆμ˜ 볡사가 μΌμ–΄λ‚˜λŠ”κ±Έ μ˜ˆμƒν• μˆ˜ μžˆλ‹€. throwμ‹œ ν•œλ²ˆ catchμ‹œ ν•œλ²ˆ ok? λΉ„νš¨μœ¨μ΄λ‹€.

참쑰둜 μ „λ‹¬ν• λ•Œ μ˜ˆμƒν•΄ 보자
~cpp 
    catch (Widget& w) ...           // μ°Έμ‘° 전달.
    catch (const Widget& w) ...     // μƒμˆ˜-μ°Έμ‘° 전달
μš°λ¦¬λŠ” μ§€κΈˆκΉŒμ§€ 볡사에 μ˜ν•œ μ§€λΆˆμ„ μƒκ°ν• μˆ˜ μžˆλŠ”λ° 참쑰의 전달은 λ°˜λŒ€λ‘œ λ³΅μ‚¬ν•˜λŠ” μž‘μ—…μ΄ μ—†λ‹€. 즉, ν•œλ²ˆμ˜ 볡사 이후 계속 같은 κ°μ²΄λΌ μ‚¬μš©ν•˜κ²Œ λ˜λŠ” μ…ˆμ΄λ‹€.

우린 아직 포인터 전달에 μ˜ν•œ κ±Έ μ˜λ…Όν•˜μ§€ μ•Šμ•˜λ‹€. ν•˜μ§€λ§Œ ν¬μΈν„°λΌ μ΄μš©ν•΄ μ˜ˆμ™ΈλΌ λ˜μ§€(전달:throw)ν•˜λŠ” 것은 ν•¨μˆ˜μƒμ—μ„œ ν¬μΈν„°λΌ μ „λ‹¬(pass)ν•˜λŠ” κ²ƒκ³ΌλŠ” λ‹€λ₯Έκ±Έ μ•Œμˆ˜ μž‡μ„ 것이닀. 즉, ν¬μΈν„°μ˜ 볡사본이 μ΄λ™ν•˜λŠ”λ°, μ΄λ ‡κ²Œ 되면 pointerλΌ μ „λ‹¬ν•˜λŠ” μͺ½μ˜ μ˜μ—­μ—μ„œ throw에 μ˜ν•΄ νŠ€μ–΄ λ‚˜κ°€λ©΄ 포인터가 가리킀고 μžˆλŠ” κ°μ²΄λŠ” μ†Œλ©Έλ˜λ€λ‘œ 포인터에 μ˜ν•œ μ˜ˆμ™Έ 전달(λ˜μ§€λŠ”κ²ƒ:throw)λŠ” ν”Όν•΄μ•Ό ν•œλ‹€. (μ „μ—­μ˜ static 객체의 포인터라면 μ΄μ•ΌκΈ°λŠ” 달라진닀. 뒀에 닀룬닀.)

자 그럼 μ˜ˆμ™ΈλΌ λ˜μ§ˆλ•Œμ˜ ν˜•μ— κ΄€ν•œ μ£Όμ˜λΌ μ‚΄νŽ΄ 보자. C++의 μ•”μ‹œμ  λ³€ν™˜μ— μ˜ν•œ 것이 κ·Έ 문제의 λ°œλ‹¨μΈλ°, μ½”λ“œλΌ λ³΄μž ν‘œμ€ μˆ˜ν•™ λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ
~cpp 
    double sqrt(double);
λΌ μ΄λ ‡κ²Œ μ‚¬μš© ν• μˆ˜ μžˆλ‹€.
~cpp 
    int i;
    double sqrtOfi = sqrt(i);
Item 5에도 μ–ΈκΈ‰λ˜μ–΄ 있λ“이 C++μƒμ—μ„œμ˜ μ•”μ‹œμ  λ³€ν™˜μ€ κ΄‘ λ²”μœ„ν•˜λ‹€. iν˜•μ˜ doubleλ³€ν™˜μ€ 가뿐? ν•˜λ‹€. ν•˜μ§€λ§Œ λ‹€μŒμ„ 보자
~cpp 
    void f (int value)
    {
        try {
            if (someFunction() ) {      // someFunction()이 참이면 intν˜•μ˜ λ³€μˆ˜λΌ μ˜ˆμ™Έλ‘œ λ˜μ§„λ‹€.
                throw value;
            }
            ...
        }
        catch (double d) {      // ν•΄λ‹Ή 핸듀은 doubleμΌλ•Œλ§Œ μ˜ˆμ™ΈλΌ μž‘μ„μˆ˜ μžˆλ‹€. 그럼 valueλΌ λ˜μ§€λŠ”
            ...                 // tryμ—μ„œμ˜ μ˜ˆμ™ΈλŠ” μ ˆλŒ€λ‘œ μž‘νžˆμ§€ μ•ŠλŠ”λ‹€. μ˜λ„ν•œ λ°”κ°€ μ•„λ‹ˆλ¦¬λΌ.
        }
        ...
    }
이런 사항을 유의 ν•΄μ•Ό ν•œλ‹€. μ˜ˆμ™Έμ—μ„œλŠ” μ•”μ‹œμ  λ³€ν™˜μ„ μƒκ°ν•˜μ§€ μ•ŠλŠ”λ‹€.

그럼 μ˜ˆμ™Έμ˜ λ³€ν™˜μ—λŠ” 크게 λ‘κ°€μ§€μ˜ 생각할 점이 μžˆλŠ”λ°. μ²«λ²ˆμ§Έκ°€ 상속 관계(μ˜ˆμ™Έ μƒμ˜) 이닀. μ˜ˆμ™Έμ—μ„œλŠ” ν•œ μ˜ˆμ™Έ κ°μ²΄μ—μ„œ νŒŒμƒλœ λ‹€λ₯Έ μ˜ˆμ™Έκ°μ²΄λ“€μ„ μž‘λŠ”κ²ƒμ΄ κ°€λŠ₯ν•œλ° 예λΌλ“€μ–΄μ„œ ν‘œμ€ C++ λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œμ˜ μ˜ˆμ™Έ μƒμ†λ„λŠ” μ΄λ ‡κ²Œ κ΅¬μ„±λ˜μ—ˆλ‹€. (λͺ¨λ“  μ˜ˆμ™Έκ°€ λ‚˜μ™”λŠ”μ§€λŠ” λͺ¨λ₯΄κ² λ‹€.)
~cpp 
    exception 
        |
        +-logic_error
        |   |
        |   +-domain_error
        |   +-invalid_argument
        |   +-length_error
        |
        +-runtime_error
            |
            +-range_error
            +-underflow_error
            +-overflow_error

catchμ—μ„œ λΆ€λͺ¨ 객체둜 작으면 μžμ‹ 객체의 μ˜ˆμ™Έλ“€μ΄ λ‹€ μž‘νžˆλŠ” 식이닀 .μ˜ˆλΌ λ“€μžλ©΄
~cpp 
catch (runtime_error) ...           // μ΄λ ‡κ²Œ μ„ μ–Έν•˜λ©΄ runtime_errorμžμ‹μΈ
catch (runtime_error&) ...          // range_error, underflow_error
catch (const runtime_error&) ...    // overflow_error이 λ‹€ μž‘νžˆλŠ” κ±°λ‹€.


catch (runtime_error*) ...          // μ΄λ ‡κ²Œ ν•˜λ©΄ runtime_error*
catch (const runtime_error*) ...    // range_error*, underflow_error*, overflow_error* 으둜 μž‘νžˆλŠ” 것이닀.

λ‘λ²ˆμ§Έμ˜ 생각할 점은 λͺ¨λ“  μ˜ˆμ™ΈλΌ μž‘κ³  μ‹ΆμœΌλ©΄
~cpp 
    catch (const void*) ...
μ΄λ ‡κ²Œ ν•˜λ©΄ μ–΄λ– ν•œ 포인터 type라도 μž‘μ„ 것이닀.

λ§ˆμ§€λ§‰μœΌλ‘œ 인자 λ„˜κΈ°κΈ°μ™€ μ˜ˆμ™Έ 전달(λ˜μ§€κΈ°:throw)의 λ‹€λ₯Έ 점은 catch ꡬ문은 항상 catchκ°€ 쓰여진 μˆœμ„œλŒ€λ‘œ (in the order of their appearance) κ΅¬λ™λœλ‹€λŠ” 점이닀. (μ˜μ–΄ ꡬ문을 μ°Έμ‘°ν•˜μ‹œκΈΈ) 말이 μ΄μƒν•˜λ‹€. κ·Έλƒ₯ λ‹€μŒ μ˜ˆμ œλΌ λ³΄μž

~cpp 
    try{
        ...
    }
    catch (logic_error& ex) {       // μ—¬κΈ°μ—μ„œ λͺ¨λ“  logicμ—λŸ¬κ°€ μž‘νžŒλ‹€.
        ...
    }
    catch (invalid_argument & ex){  // 이 문은 μž‘λ™μ„ ν•˜μ§€ μ•ŠλŠ”λ‹€. μœ„μ˜ catchκ΅¬λΆ„μ—μ„œ μ΄λΈ μž‘μ•„ 버린닀.
        ...
    }

λ°˜λŒ€λ‘œ κ°€μƒν•¨μˆ˜λΌ λΆ€λΌλ•Œ μΌμ–΄λ‚˜λŠ”μΌμ΄ μžˆλ‹€. 당신이 κ°€μƒν•¨μˆ˜λΌ ν˜ΈμΆœν•˜λ©΄ ν•¨μˆ˜λŠ” ν•΄λ‹Ή 객체의 κ°€μž₯ ν•©λ‹Ήν•œ ν•¨μˆ˜λΌ dynamic으둜 μ°Ύμ•„λ‚Έλ‹€. 이것은 졜고둜 μ ν•©ν•œ 것(best fit)을 의λΈν•˜μ§€ κ°€μž₯ μ²˜μŒμ— μ°Ύμ•„ μ§€λŠ” 것(first fit)을 의λΈν•˜λŠ” 것이 μ•„λ‹ˆλ‹€. μœ„μ˜ μ†ŒμŠ€λΌ λ°˜λŒ€λ‘œ ν•œλ‹€λ©΄

~cpp 
    try{
        ...
    }
    catch (invalid_argument & ex){  // invalid_argument μ˜ˆμ™ΈλŠ” μ΄κ³³μ—μ„œ μž‘νžŒλ‹€.
        ...
    }
    catch (logic_error& ex) {       // μ—¬κΈ°μ„œ λͺ¨λ“  λ‹€λ₯Έ logic_error 관련은 μ΄κ³³μ—μ„œ μž‘νžŒλ‹€.
        ...
    }
μ΄λ ‡κ²Œ λŒμ•„κ°€λŠ” κ±°λ‹€.

자자 정리
  • 첫째둜 μ˜ˆμ™Έ κ°μ²΄λŠ” 항상 볡사 λœλ‹€.
  • λ‘˜μ§Έλ‘œ λ˜μ €μ§€λŠ” κ°μ²΄λŠ” ν•¨μˆ˜λ‘œ μ „λ‹¬λ λ•Œ λΉ„ν•˜μ—¬ ν˜•μ— λŒ€ν•œ λ³€ν™˜μ΄ ν˜•μ— 영ν–₯ λ°›κΈ° 쉽닀.
    μ˜ˆμ™Έ κ°μ²΄λŠ” 상속에 κ·œμΉ™μ„ λ”°λ₯Έλ‹€. (μ„λͺ…을 λ³΄μ‹œκΈΈ)
  • μ…‹μ§Έλ‘œ μ†ŒμŠ€ μ½”λ“œμ— λ‚˜νƒ€λ‚˜λŠ” μˆœμ„œλŒ€λ‘œ μ˜ˆμ™ΈλŠ” μž‘νžŒλ‹€.

1.5. Item 13: Catch exception by reference

  • Item 13: μ˜ˆμ™ΈλŠ” μ°Έμ‘°(reference)둜 μž‘μ•„λΌ.

catch ꡬ문을 μ‚¬μš©ν• λ•Œ ν•΄λ‹Ή ꡬ문을 ν†΅ν•΄μ„œ 전달받은 μ˜ˆμ™Έ 객체듀을 λ°›λŠ” 방법을 μž˜μ•Œμ•„μ•Ό ν•œλ‹€. 당신은 μ„Έκ°€μ§€μ˜ 선택을 ν• μˆ˜ μžˆλ‹€. λ°”λ‘œ μ „ Item 12μ—μ„œ μ–ΈκΈ‰ν•œ κ²ƒμ²˜λŸΌ κ°’(by value), μ°Έμ‘°(by reference), 포인터(by pointer)μ΄λ ‡κ²Œ 세가지 정도가 될것이닀.

자, λ¨Όμ € pointer(by pointer)에 κ΄€ν•œ 전달을 생각해 보자. 이둠적으둜 이 방법은 throwμœ„μΉ˜μ—μ„œ catchκ΅¬λΆ„μœΌλ‘œ μ˜ˆμ™ΈλΌ νŠΉλ³„ν•œ λ³€ν™” 없이 느린 ν”„λ‘œκ·Έλž¨ μˆ˜ν–‰ μƒνƒœμ—μ„œ μ „λ‹¬ν•˜κΈ°μ— κ°€μž₯ 쒋은 방법이닀. κ·Έ μ΄μœ λŠ” ν¬μΈν„°μ˜ 전달은 ν•΄λ‹Ή μ˜ˆμ™Έ 객체가 λ³΅μ‚¬λ˜λŠ” 일없이 포인터 κ°’λ§Œ μ „λ‹¬λ˜λŠ” λ°©λ²•λ§Œμ„ μ·¨ν•΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. 말이 μ€ μ΄μƒν•œλ° μ˜ˆμ™ΈλΌ λ³΄λ©΄μ„œ μ„λͺ…ν•œλ‹€.

Item 12μ—μ„œ μ–ΈκΈ‰ν•œκ²ƒκ³Ό 같이 μ˜ˆμ™ΈλŠ” λ³΅μ‚¬λ˜μ–΄μ„œ μ „λ‹¬λœλ‹€. κ·Έκ±Έ 생각해라.
~cpp 
    class exception { ... };

    void someFunction()
    {
        static exception ex;        // μ΄λ ‡κ²Œ λ©”λͺ¨λ¦¬μ— 항상 μ‘΄μž¬ν•˜λŠ” κ°μ²΄λ§Œμ„ μ „λ‹¬ν• μˆ˜ μžˆλ‹€.
        ...
        throw &ex;    // ν¬μΈν„°λ‘œ 전달, ν•΄λ‹Ή ν•¨μˆ˜ μ˜μ—­μ„ λ²—μ–΄λ‚˜λ€λ‘œ, static만이 μ‚΄μ•„ λ‚¨μ„μˆ˜ μžˆλ‹€.
        ...
    }
    void doSomething()
    {
        try{
            someFunction();         // μ—¬κΈ°μ—μ„œ exception *을 λ˜μ§„λ‹€.
        }
        catch ( exception *ex) {    // exception* 을 작고 μ•„λ¬΄λŸ° 객체도 λ³΅μ‚¬λ˜μ§€ μ•ŠλŠ”λ‹€.
            ...
        }
    }

이 μ½”λ“œλŠ” κΉ¨λ—ν•˜κ²Œ λ³΄μ΄μ§€λ§Œ, μ΅œμ„ μ±…μ€ μ•„λ‹ˆλ‹€. 이런 일을 μœ„ν•΄μ„œ ν”„λ‘œκ·Έλž˜λ¨ΈλŠ” μ˜ˆμ™Έ κ°μ²΄λΌ ν•­μƒ ν’ˆκ³ μžˆλŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•΄μ•Ό 할것이닀. κ°„λ‹¨νžˆ μ „μ—­(Global) staitc으둜 μ„ μ–Έν•˜λ©΄ λœλ‹€κ³  λ°˜λ¬Έν•˜κ² μ§€λ§Œ, μ „μ—­μ˜ μœ„ν—˜μ„±μ€ ν”„λ‘œκ·Έλž˜λ¨Έκ°€ κ·Έκ±Έ μ‰½κ²Œ κΉŒλ¨Ήμ„μˆ˜ μžˆλ‹€λŠ”λ° μžˆλ‹€. λ‹€μŒ μ˜ˆμ œλΌ λ³΄λ©΄
~cpp 
void someFunction()
{
    exception ex;       // local μ˜ˆμ™Έ 객체인데 이 ν•¨μˆ˜μ˜ μ˜μ—­μ„ λ²—μ–΄λ‚˜λ©΄ νŒŒκ΄΄λ˜μ–΄ 진닀.

    ...
    throw &ex;          // 그럼 이건 말짱 ν—›μΌμ΄λΌλŠ” μ†Œλ¦¬ μ΄λΈ νŒŒκ΄΄λœ κ°μ²΄λΌ κ°€λ¦¬ν‚€κ³  μžˆμœΌλ‹ˆ
    ...
}
자 이건 λ‚˜μœ μ½”λ“œμ˜ μœ ν˜•μΌ 것이닀. μ£Όμ„μ—μ„œ μ–ΈκΈ‰ν•œκ²ƒκ³Ό 같이 ν•¨μˆ˜μ—μ„œ λ²—μ–΄λ‚˜λ©΄ newλ‚˜ static이 μ•„λ‹Œμ΄μƒ λ§Œλ“€μ–΄μ§„ κ°μ²΄λŠ” νŒŒκ΄΄λ˜μ–΄ 진닀. 그리고 catchμ—μ„œλŠ” νŒŒκ΄΄λ˜μ–΄μ§„ 객체의 μ£Όμ†Œ 값을 λ°›κ²Œ λ˜λŠ” 것이닀.

ν•΄λ‹Ή μ½”λ“œλΌ λ‹€μŒκ³Ό 같이 new heap object둜 λŒ€μ²΄ν• μˆ˜ μžˆμ„ 것이닀.
~cpp 
    void someFunction() 
    {
        ...
        throw new exception;    // 이것도 어폐가 μžˆλŠ”κ²Œ, newμ—μ„œ μ˜ˆμ™Έ λ°œμƒν•˜λ©΄ μ–΄λ–»κ²Œ 할것가?
        ...
    }

이것도 ν”Όν•΄μ•Ό ν•  방법이닀. μ™œλƒν•˜λ©΄ I-just-caught-a-pointer-to-a-destoyed-object 문제 λ•Œλ¬Έμ΄λ‹€. κ²Œλ‹€κ°€ catchκ΅¬λ¬Έμ—μ„œ μ§λ©΄ν•œ λ˜ν•˜λ‚˜μ˜ λ¬Έμ œλŠ” λŒ€μ²΄ 이 ν¬μΈν„°λΌ λˆ„κ°€ μ–΄λ””μ„œ μ§€μš°λŠλƒ 이닀. λ‹€λ₯Έ 면으둜 생각해볼 λ¬Έμ œλŠ” μ˜ˆμ™Έ 객체가 heap상에 λ°°μΉ˜λœλ‹€λ©΄ μ§€μ›Œ 지지 μ•Šμ€ μ˜ˆμ™Έ κ°μ²΄λŠ” ν‹€μž„μ—†μ΄ resource leakλΌ λ°œμƒ μ‹œν‚¬ 것이닀. λ„ˆλ¬΄ λ»”ν•œ 이야기 인가. 그리고 ν”„λ‘œκ·Έλž¨μ˜ 행보가 μ–΄λ–»κ²Œ 될지 예츑 ν• μˆ˜λ„ μ—†λ‹€. μ•ˆκ·ΈλŸ°κ°€?

λͺ‡λͺ‡ ν΄λΌμ΄μ–ΈνŠΈλŠ” μ „μ—­(global)μ΄λ‚˜ 정적 객체λΌ(static object)의 μ£Όμ†ŒλΌ λ„˜κΈ°μžκ³  λ§ν•˜κ³ , λͺ‡λͺ‡μ€ heapμƒμ˜ μ˜ˆμ™Έ 객체의 μ£Όμ†ŒλΌ μ „λ‹¬ν•˜μžκ³  λ§ν•œλ‹€. 이처럼 ν¬μΈν„°λΌ ν†΅ν•œ μ˜ˆμ™Έμ˜ 전달은 (Catch by pointer) μ•„λ¦¬μ†‘ν•œ λ¬Έμ œλΌ λ°œμƒ μ‹œν‚¨λ‹€. μ§€μ›Œ μ‘ŒλŠ”κ°€? μ•ˆμ§€μ›Œ μ‘ŒλŠ”κ°€? 항상 λŒ€λ‹΅μ€ ν™•μ‹€ν•˜μ§€ μ•Šλ‹€.

κ²Œλ‹€κ°€ catch-by-pointer(ν¬μΈν„°λΌ ν†΅ν•œ μ˜ˆμ™Έ 전달)은 μ–Έμ–΄μƒμ—μ„œ μ‚¬λžŒλ“€μ˜ λŒ€λ¦½μ„ μœ λ„ ν•œλ‹€. λ„κ°€μ§€μ˜ ν‘œμ€ μ˜ˆμ™Έ 객체듀듀( bad_alloc(Item 8:operator newμ—μ„œ λΆˆμΆ©λΆ„ν•œ λ©”λͺ¨λ¦¬ λ°˜ν™˜), bad_cast(Item 2:dynamic_castμ—μ„œ μ°Έμ‘° μ‹€νŒ¨), bad_typeid(dynamic_castμΌλ•Œ nullν¬μΈν„°λ‘œ λ³€ν™˜), bad_exception(Item 14:예츑 λͺ»ν•˜λŠ” μ˜ˆμ™Έλ‘œ λΉ μ§€λŠ” 것 unexpected exception 문제) κ°€ μ˜ˆμ™Έ κ°μ²΄λ“€μ˜ λͺ¨λ“  것인데, 이듀을 ν–₯ν•œ 기본적인 ν¬μΈν„°λŠ” μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€. κ·Έλž˜μ„œ 당신은 μ˜ˆμ™ΈλΌ κ°’μœΌλ‘œ(by value)ν˜Ήμ€ 참쑰둜(by reference) λ°–μ—λŠ” λŒ€μ•ˆμ΄ μ—†λ‹€.

Catch-by-valueλŠ” ν‘œμ€ μ˜ˆμ™Έ 객체듀 μƒμ—μ—μ„œ μ˜ˆμ™Έ 객체의 μ‚­μ œ λ¬Έμ œμ— κ΄€ν•΄μ„œ κ³ λΌν•  ν•„μš”κ°€ μ—†λ‹€. ν•˜μ§€λ§Œ μ˜ˆμ™Έκ°€ μ „λ‹¬λ λ•Œ λ‘λ²ˆμ˜ 볡사가 이루어 μ§„λ‹€λŠ”κ²Œ λ¬Έμ œλ‹€. (Item 12μ°Έκ³ ) κ²Œλ‹€κ°€ κ°’μœΌλ‘œμ˜ 전달은 slicing problemμ΄λΌλŠ” λ¬Έμ œλΌ λ°œμƒμ‹œν‚¨λ‹€. 이게 뭐냐 ν•˜λ©΄, λ§Œμ•½ ν‘œμ€ μ˜ˆμ™Έ κ°μ²΄μ—μ„œ μœ λ„(상속)ν•΄μ„œ λ§Œλ“€μ–΄μ§„ μ˜ˆμ™Έ 객체듀이 ν•΄λ‹Ή 객체의 λΆ€λͺ¨λ‘œ λ˜μ € 진닀면, λΆ€λͺ¨ 파트 λΆ€λΆ„λ§Œ κ°’μœΌλ‘œ λ‘λ²ˆμ§Έ λ³΅μ‚¬μ‹œμ— λ³΅μ‚¬λ˜μ–΄μ„œ μ „λ‹¬λ˜μ–΄ λ²„λ¦°λ‹€λŠ” λ¬Έμ œλ‹€. 즉 μž˜λΌλ²„λ¦¬λŠ” 문제 "slice off" λΌλŠ” ν‘œν˜„μ΄ λ“€μ–΄ 갈만 ν•˜κ² μ§€. κ·Έλ“€μ˜ data memberλŠ” μ•„λ§ˆ λΆ€μ±ν•¨μ΄ 생겨 버릴 것이고 ν•΄λ‹Ή κ°μ²΄μƒμ—μ„œ 가상 ν•¨μˆ˜λΌ λΆ€λΌλ•Œ μ—­μ‹œ λ¬Έμ œκ°€ λ°œμƒν•΄ 버릴 것이닀. μ•„λ§ˆ 무쑰건 λΆ€λͺ¨ 객체의 가상 ν•¨μˆ˜λΌ λΆ€λ₯΄κ²Œ 될 것이닀.(이 같은 λ¬Έμ œλŠ” ν•¨μˆ˜μ— κ°μ²΄λΌ κ°’μœΌλ‘œ λ„˜κΈΈλ•Œλ„ λ˜‘κ°™μ΄ 제기 λœλ‹€.) μ˜ˆλΌ λ“€μ–΄μ„œ λ‹€μŒμ„ 생각해 보자
~cpp 
    class exception {
    public:
        virtual const char * what() throw();
        ...
    }

    class runtime_error:public exception{ ... };

    class Validation_error : public runtime_error{      // 자 ν•΄λ‹Ή κ°μ²΄λŠ” runtime_errorλΌ μƒμ†ν•΄μ„œ λ§Œλ“€μ—ˆκ³ 
    public:             
        virtual const char * what() throw();            // 이 κ°€μƒν•¨μˆ˜λŠ” exception상에 μžˆλŠ” 것이닀.
        ...
    }
    void someFunction()
    {
        ...
        if ( a validation ν…ŒμŠ€νŠΈ μ‹€νŒ¨){
            throw Validation_error();
        }
        ...
    }
    void doSomething()
    {
        try{
            someFunction();
        }
        catch (exception ex) {      // item 12μ—μ„œ μ–ΈκΈ‰ν–ˆλ“ exception의 μžμ‹ μ˜ˆμ™Έκ°μ²΄λ“€μ€ λ‹€ μž‘νžŒλ‹€.
            cerr << ex.what();      // κ°’μœΌλ‘œ λΆ€λͺ¨λ§Œ λ³΅μ‚¬ν–ˆκΈ° λ•Œλ¬Έμ— what() κ°€μƒν•¨μˆ˜λŠ” exceptionμƒμ˜ 
                                    // 가상 ν•¨μˆ˜κ°€ λΆˆλ¦°λ‹€. 개발자의 μ˜λ„λŠ” Validation_error μƒμ˜ κ°€μƒν•¨μˆ˜λΌ
                                    // λΆ€λ₯΄κΈΈ μ›ν•˜λŠ” 것 μ΄μ—ˆλ‹€.
            ...
        }
    }
주석에 μ–ΈκΈ‰λ˜μ–΄ 있λ“이 이 버전은 slicing λ¬Έμ œκ°€ λ°œμƒν•œλ‹€. κ΅¬μ°¨ν•œ μ„λͺ… κ·€μ°λ‹€. 결둠은 κ°’μœΌλ‘œ(by value)의 μ˜ˆμ™Έ 객체 전달은 이런 slicing 문제둜 당신이 μ›ν•˜λŠ” 행동을 μ ˆλŒ€λ‘œ λͺ»ν•œλ‹€.

자자 그럼 남은건 였직 catch-by-reference(μ°Έμ‘°λ‘œμ„œ μ˜ˆμ™Έ 전달)이닀. catch-by-referenceλŠ” μ΄μ œκΉŒμ§€μ˜ λ…Όμ˜λΌ κΉ¨λ—μ΄ μ—†μ•  μ€λ‹€. catch-by-pointer의 객체 μ‚­μ œ λ¬Έμ œμ™€ ν‘œμ€ μ˜ˆμ™Έ νƒ€μž…λ“€μ„ μž‘λŠ”κ±°μ— λŒ€ν•œ 어렀움, catch-by-value와 같은 slicing λ¬Έμ œλ‚˜ λ‘λ²ˆ λ³΅μ œλ˜λŠ” 어렀움이 μ—†λ‹€. μ°Έμ‘°λ‘œμ„œ μ˜ˆμ™Έ μ „λ‹¬μ—μ„œ μ˜ˆμ™Έ κ°μ²΄λŠ” 였직 ν•œλ²ˆ λ³΅μ‚¬λ˜μ–΄ 질 뿐이닀.

λ‹€μŒ μ˜ˆμ œλΌ λ³΄μž.
~cpp 
void someFunction()
{
    ...
    if ( validation ν…ŒμŠ€νŠΈ μ—λŸ¬ ){
        throw Validataion_error();
    }
    ...
}

void doSomething()
{
    try{
        someFunction();
    }
    catch (exception& ex){      // 이뢀뢄을 참쑰둜만 λ°”κΎΈμ—ˆλ‹€. μ΄μ „μ˜ μ˜ˆμ œμ™€ νŠΉλ³„νžˆ λ°”λ€κ²Œ μ—†λ‹€.
                                // ν•˜μ§€λ§Œ 이뢀뢄이 λ°”λ€Œμ–΄μ„œ
        cerr << ex.what();      // μ—¬κΈ°μ„œμ˜ 가상 ν•¨μˆ˜λ„ Validation_error의 λ©”μ†Œλ“œκ°€ λΆˆλ¦°λ‹€.
        ...
    }
}

ν•΄λ‹Ή μ†ŒμŠ€λŠ” catchμ—μ„œ 참쑰둜만이 λ°”λ€Œμ—ˆλ‹€. &ν•˜λ‚˜λ§Œμ΄ μΆ”κ°€λ˜μ–΄ μ§€κΈˆκΉŒμ§€ 제기된 λ¬Έμ œκ°€ 사라져 버린닀.

catch-by-referenceλŠ” μ΄μ œκΉŒμ§€μ˜ λ¬Έμ œμ— λͺ¨λ“  해결책을 μ œμ‹œν•œλ‹€. (slicing, delete문제 etc)그럼 이제 결둠은 ν•˜λ‚˜ μ•„λ‹κΉŒ?

Catch exception by reference!

1.6. Item 14: Use exception specifications judiciously.

  • Item 14: μ˜ˆμ™ΈλΌ μ‹ μ€‘ν•˜κ²Œ μ‚¬μš©ν•˜λΌ.
(judiciously- μ‹ μ€‘ν•œ)

일단 이 μ£Όμ œλΌ λΆ€μ •ν•˜λŠ” μ΄λŠ” μ—†μœΌλ¦¬λΌ.:μ˜ˆμ™ΈλŠ” μ μ ˆν•œ 곳에 ν‘œν˜„λ˜μ–΄μ•Ό ν•œλ‹€. 그듀은 μ½”λ“œλΌ λ” 이해가기 νŽΈν•˜κ²Œ λ§Œλ“€μ–΄ μ€λ‹€. μ™œλƒν•˜λ©΄ μ•„λ§ˆ λͺ…μ‹œμ μœΌλ‘œ ν‘œν˜„λœ μ˜ˆμ™Έ μƒνƒœκ°€ 전달(λ˜μ €:throw-μ΄ν•˜ λ˜μ§„λ‹€λŠ” ν‘œν˜„μœΌλ‘œ) 될 것이기 λ•Œλ¬Έμ΄λ‹€. κ·Έλ ‡μ§€λ§Œ μ˜ˆμ™ΈλŠ” 주석(comment)λ³΄λ‹€λŠ” λͺ¨ν˜Έν•˜λ‹€. μ»΄νŒŒμΌλŸ¬λŠ” λ•Œλ•Œλ‘œ μ»΄νŒŒμΌμ€‘μ— μ •ν™•νžˆ μΌμΉ˜ν•˜μ§€ μ•Šμ€ μ˜ˆμ™Έλ“€μ„ λ°œκ²¬ν• μˆ˜λ„ 있으며, λ§Œμ•½ ν•¨μˆ˜κ°€ μ˜ˆμ™Έ μŠ€νŽ™(λͺ…μ„Έ:μ΄ν•˜λͺ…μ„Έ)상에 μ œλŒ€λ‘œ λͺ…κΈ°λ˜μ§€ μ•Šμ€ μ˜ˆμ™ΈλΌ μ „λ‹¬(던쑌)λ‹€λ©΄ 잘λͺ»μ€ μ‹€ν–‰μ‹œκ°„(runtime)에 λ°œκ²¬λœλ‹€. 그리고 νŠΉλ³„ν•œ ν•¨μˆ˜μΈ unexpectedλŠ” μžλ™μœΌλ‘œ 뢈리게 λœλ‹€. 이렇든 μ˜ˆμ™Έμ²˜λ¦¬λŠ” μƒλ‹Ήνžˆ 맀λ ₯적인 면을 가지고 μžˆλ‹€.

  • ν•˜μ§€λ§Œ 보톡 아름닀움은 ν‘œλ©΄μ΄ μ•„λ‹Œ 내면에 μ‘΄μž¬ν•œλ‹€.
unexpected에 κ΄€λ ¨ν•œ 기본적인 행동은 terminateλΌ ν˜ΈμΆœν•΄μ„œ terminateλ‚΄μ—μ„œ abortλΌ ν˜ΈμΆœλ‘œ κ°•μ œλ‘œ ν”„κ·Έλž¨μ„ λ©ˆμΆ”κ²Œ ν•œλ‹€. 이 의λΈλŠ” λ°”λ‘œ abortλŠ” ν”„λ‘œκ·Έλž¨μ„ μ’…λ£Œν• λ•Œ 깨끗이 μ§€μš°λŠ” 과정을 μƒλž΅ν•˜κΈ° λ•Œλ¬Έμ— ν™œμ„±ν™”λœ μŠ€νƒ ν”„λ ˆμž„λ‚΄μ˜ 지역 λ³€μˆ˜λŠ” νŒŒκ΄΄λ˜μ§€ μ•ŠλŠ”λ‹€.(즉, ν”„λ‘œκ·Έλž¨μ΄ λ©ˆμΆ”κ³  λ””λ²„κ·Έμ‹œ κ·Έ 상황에 ν˜„μž¬μ˜ 자료 값을 μ‘°μ‚¬ν• μˆ˜ μžˆλ‹€λŠ” 의λΈ). κ·Έλž˜μ„œ μ˜ˆμ™Έ 처리의 λͺ…세을 μ–΄κΈ΄ λ¬Έμ œλŠ” μƒλ‹Ήνžˆ μ‹¬κ°ν•œ μƒν™©μ΄λ‚˜, 거의 λ°œμƒν•˜μ§€ μ•Šμ€ 상황이닀. λΆˆν–‰νžˆλ„ 그런 μ‹¬κ°ν•œ 상황을 이λ₯΄κ²Œ ν•˜λŠ” ν•¨μˆ˜ μž‘μ„±μ΄ μš©μ΄ν•˜λ‹€λŠ”κ²Œ λ¬Έμ œμ΄λ‹€. μ»΄νŒŒμΌλŸ¬λŠ” 였직 μ˜ˆμ™Έ λͺ…세에 μž…κ°ν•œλŒ€λ‘œ λΆ€λΆ„μ μœΌλ‘œ μ˜ˆμ™Έ μ‚¬μš©μ— κ΄€ν•œ κ²€μ‚¬λΌ ν•œλ‹€. μ˜ˆμ™Έκ°€ μž‘μ„μˆ˜ μ—†λŠ”κ²ƒ-μ–Έμ–΄ ν‘œμ€ μƒμ—μ„œ κ±°λΆ€ν•˜λŠ”(비둝 주의(wanning)일지라도) κΈˆμ§€ν•˜λŠ” 것- 은 ν•¨μˆ˜λΌ ν˜ΈμΆœν• λ•Œ μ˜ˆμ™Έ λͺ…μ„Έμ—μ„œ λ²—μ–΄λ‚˜λŠ” ν•¨μˆ˜μΌκ²ƒμ΄λ‹€.

λ‹€μŒμ˜ f1ν•¨μˆ˜μ— 같이 μ•„λ¬΄λŸ° μ˜ˆμ™ΈλΌ λ°œμƒ μ•ˆμ‹œν‚€λŠ” ν•¨μˆ˜μ— κ΄€ν•΄μ„œ 생각해 보자. μ €λŸ° ν•¨μˆ˜λŠ” μ•„λ§ˆ μ–΄λ– ν•œ μ˜ˆμ™ΈλΌλ„ λ°œμƒμ‹œν‚¬μˆ˜ μžˆμ„ 것이닀.
~cpp 
    extern void f1();
자 그럼 μ˜ˆμ™Έ λͺ…세이 적용된 f2λΌ λ³΄μž. λ‹€μŒμ€ 였직 intλ§Œμ„ μ˜ˆμ™Έλ‘œ λ˜μ§ˆκ²ƒμ΄λ‹€.
~cpp 
    void f2() throw(int);
f1이 f2의 ν•¨μˆ˜ λͺ…μ„Έκ³Ό λ‹€λ₯Έ μ˜ˆμ™ΈλΌ λ˜μ§€λ”λΌλ„, C++μƒμ—μ„œλŠ” f2μ—μ„œ f1λΌ λΆ€λ₯΄λŠ”것을 ν—ˆμš©ν•œλ‹€.
~cpp 
    void f2() throw(int)
    {
        ...
        f1();
        ...
    }
이런 μœ μ—°ν•œ κ²½μš°λŠ” λ§Œμ•½ μ˜ˆμ™Έ λͺ…세에 κ΄€ν•œ μƒˆλ‘œμš΄ μ½”λ“œκ°€ 과거의 μ˜ˆμ™Έ λͺ…μ„Έκ°€ λΆ€μ±ν•œ μ½”λ“œμ™€ 잘 κ²°ν•©ν• μˆ˜ μžˆμŒμ„ 보인닀.

λ‹Ήμ‹ μ˜ μ»΄νŒŒμΌλŸ¬κ°€ μ˜ˆμ™Έ μ²˜λ¦¬κ·œμ •μ— 만μ±ν•˜μ§€ μ•Šμ€ 루틴을 가진 ν•¨μˆ˜μ˜ μ½”λ“œλΌ ν˜ΈμΆœν•˜λŠ”λ° 별 무리없닀고, κ·ΈλŸ¬ν•œ 호좜이 μ•„λ§ˆ λ‹Ήμ‹ μ˜ ν”„λ‘œκ·Έλž¨μ—μ„œ ν”„λ‘œκ·Έλž¨μ˜ μ€‘μ§€λΌ μœ λ„ν•˜κΈ° λ•Œλ¬Έμ— 당신은 μ†Œν”„νŠΈμ›¨μ–΄λΌ λ§Œλ“€λ•Œ μ΅œλŒ€ν•œ 그런 만μ±λ˜μ§€ μ•Šμ€ ν˜ΈμΆœμ„ μ΅œμ†Œν™” ν•˜λ„λ‘ κ²°κ³ΌλΌ μœ λ„ν•΄μ•Ό 할것이닀. μ‹œμž‘μ‹œ κ°€μž₯ 쒋은 λ°©ν–₯은 ν…œν”Œλ¦Ώμƒμ—μ„œμ˜ μ˜ˆμ™Έ μŠ€νŽ™λΌ μ΅œλŒ€ν•œ ν”Όν•˜λŠ” 것이닀. 자 λ‹€μŒμ˜ μ–΄λ– ν•œ μ˜ˆμ™Έλ„ λ˜μ§€μ§€ μ•Šμ€ ν…œν”Œλ¦Ώμ„ 생각해 보자.
~cpp 
    template<class T>
    bool operator==(const T& lhs, const T& rhs) throw()
    {
        return &lhs == &rhs;
    }
이 ν…œν”Œλ¦Ώμ€ oprator== ν•¨μˆ˜λΌ λͺ¨λ“  ν˜•μ— μ μš©μ‹œν‚€λŠ” 것이닀. μ•„λ§ˆ 같은 μ£Όμ†Œμ— 같은 νƒ€μž…μ΄λ©΄ trueλΌ λ°˜ν™˜ν•˜μ§€λ§Œ μ•„λ‹ˆλΌλ©΄ 그것은 falseλΌ λ°˜ν™˜ν•œλ‹€. 이런 ν…œν”Œλ¦Ώμ€ μ•„λ¬΄λŸ° μ˜ˆμ™Έλ„ λ˜μ§€μ§€ μ•Šμ€ ν…œν”Œλ¦ΏμœΌλ‘œ λΆ€ν„° ν•¨μˆ˜κ°€ λ§Œλ“€μ–΄μ§€λŠ” μƒνƒœμ— 따라 μ ν•©ν•œ μ˜ˆμ™Έκ°€ ν¬ν•¨λœλ‹€. ν•˜μ§€λ§Œ 그것은 κΌ­ 사싀이 μ•„λ‹ˆλ‹€. μ™œλƒν•˜λ©΄ operator&(μ£Όμ†Œ λ°˜ν™˜ operator)κ°€κ°€ κΌ­ 같은 λͺ‡λͺ‡μ˜ ν˜•λ“€μ„ μœ„ν•΄μ„œ overloadλ˜μ—ˆκΈ° λ•Œλ¬Έμ΄λ‹€. λ§Œμ•½ 사싀이 κ·ΈλŸ¬ν•˜λ‹€λ©΄ operaotr&κ°€ operator== μ•ˆμͺ½μ—μ„œ λΆˆλ¦΄λ•Œ μ˜ˆμ™ΈλΌ λ˜μ§ˆ 것이닀. κ·Έλ ‡κ²Œ 되면 우리의 μ˜ˆμ™Έ λͺ…μ„ΈλŠ” κ±°λΆ€λ˜κ³ , 곧μž₯ unexpected 둜 μ§μ§„ν•˜κ²Œ λ˜λŠ”κ±°λ‹€.

μ΄λŸ¬ν•œ νŠΉλ³„λ‚œ μ˜ˆμ œλŠ” 더 일반적인 문제둜, λ‹€μ‹œ λ§ν•˜μžλ©΄ ν…œν”Œλ¦Ώμ˜ ν˜• 인자둜 μ „λ‹¬λ˜λŠ” μ˜ˆμ™Έμ— κ΄€ν•œ μ •λ³΄λΌ μ•Œμ•„λ‚Ό 길이 μ—†λ‹€λŠ” 점도 ν•œλͺ«μ΄λ‹€. μš°λ¦¬λŠ” 거의 ν…œν”Œλ¦Ώμ„ μœ„ν•œ 의λΈμžˆλŠ” μ˜ˆμ™Έ λͺ…μ„ΈλΌ μ œκ³΅ν• μˆ˜ μ—†λ‹€λŠ” 이야기닀. μ™œλƒν•˜λ©΄ ν…œν”Œλ¦Ώμ€ 거의 변함없이 그듀이 ν˜• μΈμžλΌ λͺ‡κ°€μ§€μ˜ λ°©μ‹μœΌλ‘œλ§Œ μ“°κΈ° λ•Œλ¬Έμ΄λ‹€. 결둠은? ν…œν”Œλ¦Ώκ³Ό μ˜ˆμ™ΈλŠ” μ–΄μšΈλ¦¬μ§€ μ•ŠλŠ”λ‹€.!

  • λ‘λ²ˆμ§Έλ‘œ 당신은 unexpectedν˜ΈμΆœμ„ λ§‰κΈ°μœ„ν•˜μ—¬ λΆ€μ±ν•œ μ˜ˆμ™Έ λͺ…μ„Έμ˜ κ·œμ •μœΌλ‘œ μΈν•˜μ—¬ λΆˆλ¦¬λŠ” ν•¨μˆ˜μƒμ—μ„œ μ˜ˆμ™Έ λͺ…μ„ΈλΌ μƒλž΅ν• μˆ˜ μžˆλ‹€.
이것은 κ°„λ‹¨ν•˜κ³  일반적인 μƒκ°μ΄μ§€λ§Œ, μžƒμ–΄λ²„λ¦¬κΈ° μ‰¬μš΄ κ²½μš°μ΄λ‹€. λ‹€μŒμ˜ callback ν•¨μˆ˜ 등둝에 κ΄€ν•œ μ˜ˆμ œλΌ λ³΄μž
~cpp 
typedef void (*CallBackPtr) (int eventXLocation, int event YLocation, void *dataToPassBack);

class CallBack{
public:
    CallBack(CallBackPtr fPtr, void *dataToPassBack) :func(fPtr), data(dataToPassBack){}

    void makeCallBack(int eventXLocation, int eventYLocation) const throw();
private:
    CallBackPtr func;
    void *data
}

    void CallBack::makeCallBack(int eventXLocation, int eventYLocation)
    {
        func(eventXLocation, eventYLocation);
    }
이 μ½”λ“œμ—μ„œ makeCallBackμ—μ„œ func을 ν˜ΈμΆœν•˜λŠ”κ²ƒμ€ func이 λ˜μ§€λŠ” μ˜ˆμ™Έμ— 것을 μ•ŒκΈΈμ΄ μ—†μ–΄μ„œ μ˜ˆμ™Έ λͺ…세에 μœ„λ°˜ν•˜λŠ” μœ„ν—˜ν•œ μƒν™©μœΌλ‘œ 갈수 μžˆλ‹€.

이런 λ¬Έμ œλŠ” λ‹€μŒκ³Ό 같이 CallBackPtrμƒμ˜ μ˜ˆμ™Έ λͺ…μ„ΈλΌ μ€λ” ꡬ체화 μ‹œμΌœμ„œ μ œκ±°ν• μˆ˜ μžˆλ‹€.
~cpp 
typedef void (*CallBackPtr) (int eventXLocation, int event YLocation, void *dataToPassBack) throw();
λ‹€μŒκ³Ό 같이 ν˜•μ΄ μ„ μ–Έλ˜μ—ˆμœΌλ©΄ callbackν•¨μˆ˜ λ“±λ‘μ‹œ 아무것도 λ˜μ§€μ§€ μ•ŠλŠ”λ‹€λŠ” 쑰건이라면 μ˜ˆμ™ΈλΌ λ°œμƒν• κ²ƒμ΄λ‹€.
~cpp 
    // μ˜ˆμ™Έ λͺ…μ„Έκ°€ μ—†λŠ” ν•¨μˆ˜
    void callBackFcn1(int eventXLocation, int event YLocation, void *dataToPassBack);
    void *vallBackData;
    ...
    CallBack c1(callBackFcn1, callBackData); // μ—λŸ¬λ‹€ callBackFcn1은 μ—¬κΈ°μ—μ„œ ν˜•μ΄ λ§žμ§€ μ•Šμ•„. μ—λŸ¬λΌ λ˜μ§ˆκ²ƒμ΄λ‹€.

    // μ˜ˆμ™Έ λͺ…μ„Έκ°€ μžˆλŠ” ν•¨μˆ˜
    void callBackFcn2(int eventXLocation, int event YLocation, void *dataToPassBack); throw()
    CallBack c1(callBackFcn2, callBackData); // λ³΄λ‹€μ‹œν”Ό μ•Œλ§žλŠ” ν˜•μ΄λ‹€.

μ΄λŸ¬ν•œ ν•¨μˆ˜ 포인터 μ „λ‹¬μ‹œ 관련은 μ΅œκ·Όμ— μΆ”κ°€λœκ±°λ‹ˆ λ§Œμ•½ μ»΄νŒŒμΌλŸ¬κ°€ 지원 λͺ»ν•œλ‹€κ³  해도 λ†€λž„κ²ƒμ€ μ—†λ‹€. (이책은 1996년에 λ‚˜μ™”λ‹€. ν•˜μ§€λ§Œ μ§€κΈˆλ„(2001년정도) μ œλŒ€λ‘œ μ§€μ›ν•˜λŠ” μ»΄νŒŒμΌλŸ¬κ°€ λ§Žμ§€ μ•Šμ€κ±Έλ‘œ μ•ˆλ‹€.) λ§Œμ•½ μ»΄νŒŒμΌλŸ¬κ°€ 처리 λͺ»ν•œλ‹€λ©΄ 이런 μ‹€μˆ˜μ˜ λ°©μ§€λŠ” λ‹Ήμ‹  μžμ‹ μ—κ²Œ 달렸닀.

  • μ„Έλ²ˆμ§Έλ‘œ 당신은 "the system"이 μ•„λ§ˆ λ˜μ§€λŠ” μ˜ˆμ™ΈλΌ ν•Έλ“€λ§ν•΄μ„œ unexcepted의 ν˜ΈμΆœμ„ ν”Όν• μˆ˜ μžˆλ‹€. μ΄λŸ¬ν•œ μ˜ˆμ™ΈλŠ” λ§Žμ€ 뢀뢄이 new와 new[]μ‹œ λ©”λͺ¨λ¦¬ ν• λ‹Ή μ˜ˆμ™Έμ—μ„œ bad_alloc이 λ°œμƒν•˜μ—¬ λ°œμƒν•œλ‹€. λ§Œμ•½ 당신이 newλΌ μ–΄λ–€ ν•¨μˆ˜μ—μ„œ μ“΄λ‹€λ©΄ μš°μ—°μ΄λΌλ„ bad_alloc μ˜ˆμ™ΈλΌ λ§Œλ‚ μˆ˜ μžˆλŠ” κ°€λŠ₯성을 λ‚΄ν¬ν•˜λŠ” μ…ˆμ΄λ‹€.

자, μ§€κΈˆ 1온슀의 μ˜ˆλ°©λŠ” μ°¨ν›„ 1νŒŒμš΄λ“œμ˜ 피해보닀 λ‚³μ§€λ§Œ λ•Œλ‘œλŠ” 예방이 μ–΄λ ΅κ³  ν”Όν•΄κ°€ 더 μ‰¬μš΄ κ²½μš°λ„ 있으리라. μ–ΈκΈ‰ν•œ κ²ƒμ²˜λŸΌ λ•Œλ•Œλ‘œ unexpected μ˜ˆμ™Έ 직접 λ§žμ„œλŠ” 것은 μ²˜μŒμ— 그것을 μ—λ°©ν•˜λŠ”κ²ƒ 보닀 쉽닀. 예λΌλ“€μžλ©΄ λ§Œμ•½ 당신이 μ˜ˆμ™Έλͺ…μ„ΈλΌ μ—„κ²©ν•˜κ²Œ μž‘μ„±ν–ˆμ§€λ§Œ 당신은 μ˜ˆμ™Έ λͺ…μ„Έκ°€ λ˜μ–΄ μžˆμ§€ μ•Šμ€ 라이브러리의 ν•¨μˆ˜λ“€μ„ κ°•μ œλ‘œ λΆ€λΌμˆ˜ μžˆλ‹€. ν•¨μˆ˜μƒμ—μ„œ μ½”λ“œλ“€μ΄ λ°”λ€ŒλŠ” μ •μ΄λΌμ„œ unexpectedμ˜ˆμ™ΈλΌ λ§‰λŠ”κ²ƒμ€ λΉ„μ‹€μš©μ μ΄λ‹€.

λ§Œμ•½ unexpectedμ˜ˆμ™ΈλΌ λ§‰λŠ”κ²ƒμ΄ μ‹€μš©μ μ΄μ§€ λͺ»ν•˜λ‹€λ©΄ 당신은 C++κ°€ unexpectedλΌ λ‹€λ₯Έ ν˜•μ‹μœΌλ‘œ λ°”κΎΈμ–΄ λ²„λ¦¬λŠ” κΈ°λŠ₯을 μ΄μš©ν•΄μ„œ κ·ΈλŸ¬ν•œ λΉ„μ‹€μš©μ μΈ μƒνƒœλΌ λ§ŒνšŒν• μˆ˜ μžˆλ‹€. λ‹€μŒ μ˜ˆλŠ” unexpect와 같은 μ˜ˆμ™ΈλΌ UnexpectedException 객체둜 바꾼것을 생각해 λ³Έλ‹€.
~cpp 
class UnexpectedException {};

void convertUnexpected()
{
    throw UnexpectedException();
}

그리고 unexpected ν•¨μˆ˜λΌ convertUnexpected둜 κ΅μ²΄ν•œλ‹€.
~cpp 
    set_unexpected(convertUnexpected);
μ΄λ ‡κ²Œ ν•˜λ©΄ unexpectedμ˜ˆμ™ΈλŠ” convertUnexpectedλΌ ν˜ΈμΆœν•œλ‹€. 즉, μƒˆλ‘œμš΄ UnexpectedException 객체둜 μ˜ˆμ™Έκ°€ κ΅μ²΄λ˜μ—ˆλ‹€. ν•˜μ§€λ§Œ μ œκ³΅λ˜λŠ” μ˜ˆμ™Έ λͺ…μ„Έμ—μ„œ unexpectedλΌ λ°©μ§€ν• λ €λ©΄ UnexpectedException μ˜ˆμ™ΈλΌ ν¬ν•¨ν•΄μ•Ό ν•œλ‹€. μ˜ˆμ™ΈλΌ κ°μ²΄λ‘œ λ˜μ‘ŒκΈ°μ—.. (λ§Œμ•½ μ˜ˆμ™Έ λͺ…세에 UnexpectedException을 넣지 μ•Šμ•˜λ‹€λ©΄ unexpectedκ°€ κ΅μ²΄λ˜μ§€ μ•Šμ€ κ²ƒμ²˜λŸΌ terminateκ°€ λΆˆλ¦΄κ²ƒμ΄λ‹€.)

또 λ‹€λ₯Έ 방법은 unexpected μ˜ˆμ™ΈλΌ κ·Έλƒ₯ unexpected의 역할을 ν˜„μž¬μ˜ μ˜ˆμ™ΈλΌ κ³„μ† λ˜μ§€κΈ°(rethrow)ν˜•νƒœλ‘œ λ°”κΎΈμ–΄ λ²„λ¦¬λŠ” 것이닀. μ΄λ ‡κ²Œ κ΅μ²΄ν•˜λ©΄ μ˜ˆμ™ΈλŠ” μ•„λ§ˆ μƒˆλ‘œμš΄ ν‘œμ€μ˜ bad_exception 을 λ˜μ§€λŠ” ν˜•νƒœλ‘œ 바뀐닀. (μ •κ·œ C++λΌμ΄λΈŒλŸ¬λ¦¬μ— 포함)
~cpp 
    void convertUnexpected()
    {
        throw()     // 이건 ν˜„μ œμ˜ μ˜ˆμ™ΈλΌ κ³„μ† λ˜μ§„λ‹€λŠ” 의λΈ
    }

    set_unexpected(convertUnexpected);
λ§Œμ•½ μœ„μ™€ 같이 ν•˜κ³  bad_exception(ν‘œμ€ λΌμ΄λΈŒλŸ¬λ¦¬ μƒμ˜ exception의 κΈ°λ³Έ μ˜ˆμ™Έ 클래슀)λΌ λ‹Ήμ‹ μ˜ λͺ¨λ“  μ˜ˆμ™Έ λͺ…세에 ν¬ν•¨μ‹œν‚€λ©΄ 당신은 κ²°μ½” λ‹Ήμ‹ γ„΄μ˜ ν”„λ‘œκ·Έλž¨μ΄ λΆˆμ‹œμ— λ©ˆμΆ”μ–΄ λ²„λ¦¬λŠ”κ²ƒμ— λŒ€ν•œ 걱정을 ν•  μš”λŠ” 없을 것이닀. κ±°κΈ°λ‹€κ°€ κ·œμ •μ— λ§žμ§€μ•ŠλŠ” μ˜ˆμ™Έλ“€λ„ bad_exception으둜 ꡐ체되고 μ˜ˆμ™ΈλŠ” κΈ°λ³Έ μ˜ˆμ™Έ λŒ€μ‹ μ— λ‹€μ‹œ λ˜μ € 퍼진닀.(propagate)

--
이제 당신은 μ˜ˆμ™Έ λͺ…μ„Έκ°€ λ§Žμ€ λ¬Έμ œλΌ κ°€μ§€κ³  μžˆμ„μˆ˜ μžˆμŒμ„ 이해 할것이닀. μ»΄νŒŒμΌλŸ¬λŠ” κ·Έλ“€μ˜ 뢀뢄적인 μ“°μž„μƒˆλΌ κ²€μ‚¬ν•΄μ„œ ν…œν”Œλ¦Ώμ—μ„œ λ¬Έμ œλΌ λ°œμƒν•  μ†Œμ§€λΌ μ•ŠμœΌλ©°, μ»΄νŒŒμΌλŸ¬λŠ” μ˜μ™Έλ‘œ κ·œμΉ™μœ„λ°˜μ„ ν•˜κΈ° 쉽고, μ»΄νŒŒμΌλŸ¬κ°€ μ œλŒ€λ‘œ λ˜μ§€ μ•ŠμœΌλ©΄ ν”„λ‘œκ·Έλž¨μ„ λΆˆμ‹œμ— λ©ˆμΆ”μ–΄ 지도둝 μœ λ„ν• κ²ƒμ΄λ‹€. μ˜ˆμ™Έ λͺ…μ„Έ μ—­μ‹œ λ˜λ‹€λ₯Έ λ¬Έμ œλΌ μ•ˆκ³  μžˆλŠ”λ°, μ˜ˆμ™Έλͺ…μ„ΈλŠ” 높은 수μ€μ˜ ν˜ΈμΆœμžκ°€ μ˜ˆμ™Έ λ°œμƒμ„ λŒ€λΉ„ν• λ•Œλ„ unexpected둜의 결과물을 λ§Œλ“€μ–΄ λ‚Έλ‹€.

μ΄μ•ΌκΈ°λΌ μœ„ν•΄ Item 11의 μ˜ˆμ œλΌ κ·ΈλŒ€λ‘œ 보자
~cpp 
    class Session{
    public:
        ~Session();
        ...
    private:
        static void logDestuction(Session *objAddr) throw();
    };

    Session::~Session()
    {
        try{
            logDestruction(this);
        }
        catch ( ... ) {}
    }
Session의 νŒŒκ΄΄μžλŠ” logDestruction을 ν˜ΈμΆœν•œλ‹€. ν•˜μ§€λ§Œ λͺ…μ‹œμž‘μ€ μ–΄λ– ν•œ μ˜ˆμ™Έλ„ ν•΄λ‹Ή logDestructionμ—μ„œ λ˜μ§€μ§€ λͺ»ν•˜λ„둝 λ§‰μ•„λ†“μ•˜λ‹€. ν•œλ²ˆ logDestuction이 μ‹€νŒ¨ν• λ•Œ λΆˆλ¦¬λŠ” ν•¨μˆ˜λ“€μ— λŒ€ν•˜μ—¬ 생각해 보자. 이것은 μ•„λ§ˆ μΌμ–΄λ‚˜μ§€ μ•Šμ„ 것이닀. μš°λ¦¬κ°€ μƒκ°ν•œλŒ€λ‘œμ΄κ±΄ μƒλ‹Ήνžˆ μ˜ˆμ™Έ λͺ…μ„Έμ˜ κ·œμ • μœ„λ°˜μœΌλ‘œ μΈλ„ν•˜λŠ” μ½”λ“œμ΄λ‹€. 이런 μ˜ˆμΈ‘ν• μˆ˜ μ—†λŠ” μ˜ˆμ™Έκ°€ logDestruction으둜 λΆ€ν„° νΌμ§ˆλ•Œ unexpectedκ°€ 풀릴 것이닀. 기본적으둜 그것은 ν”„λ‘œκ·Έλž¨μ„ λ©ˆμΆ˜λ‹€. 이 μ˜ˆμ œλŠ” κ·Έκ²ƒμ˜ μˆ˜μ • λ²„μ „μ΄μ§€λ§Œ, 그런 μˆ˜ν–‰μ„ Session 파괴자의 μ œμž‘μžκ°€ μ›ν• κΉŒ? μž‘μ„±μžλŠ” λͺ¨λ“  κ°€λŠ₯ν•œ μ˜ˆμ™Έ λΌ μž‘μœΌλ €κ³  λ…Έλ ₯ν•œλ‹€. κ·Έλž˜μ„œ 그건 Session 파괴자의 catchλΈ”λŸ­μ—μ„œμˆ˜ν–‰λ˜λŠ” 것이 λ‹€λ‹€λ©΄ 그건 λΆˆκ³΅ν‰ν•œ μ²˜μ‚¬λΌκ³  보인닀. λ§Œμ•½ logDestruction이 μ•„λ¬΄λŸ° μ˜ˆμ™Έ λͺ…μ„ΈλΌ ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄, I'm-willing-to-catch-it-if-you'll-just-give-me-a-chance μ‹œλ‚˜λ¦¬μ˜€λŠ” κ²°μ½” μΌμ–΄λ‚˜μ§€ μ•Šμ„κ²ƒμ΄λ‹€. (이런 문제의 예방으둜 unexpected의 ꡐ체에 λŒ€ν•œ μ„λͺ…을 μœ„ν•΄ μ–ΈκΈ‰ν•΄ λ‘μ—ˆλ‹€.)

μ˜ˆμ™Έ λͺ…μ„Έμ˜ κ· ν˜•μžˆλŠ” μ‹œκ°μ€ μ€‘μš”ν•œκ²ƒμ΄λ‹€. 그것은 μ˜ˆμ™Έ λ°œμƒμ„ μ˜ˆμƒν•˜λŠ” ν•¨μˆ˜λ“€μ˜ μ˜ˆμ™Έ μ’…λ₯˜λ“€μ„ 보면 ν›Œλ₯­ν•œ λ¬Έμ„œν™”κ°€ 될것이고, 잘λͺ»λœ μ˜ˆμ™Έ λͺ…μ„Έμ˜ μƒν™©ν•˜μ˜ ν”„λ‘œκ·Έλž¨μ€ 기본적으둜 μ£Όμ–΄μ§€λŠ” μƒνƒœ 즉, μ¦‰μ‹œ λ©ˆμΆ”λŠ” 것을 μ •λ‹Ήν™”ν•  만큼 잘λͺ»λœ 일이닀. 같은 μ‹œκ°μœΌλ‘œ μ˜ˆμ™ΈλŠ” μ»΄νŒŒμΌλŸ¬μ— μ˜ν•˜μ—¬ 였직 뢀뢄적인 μ κ²€λ§Œμ„ λ‹Ήν•˜κ³  μ˜ˆμ™ΈλŠ” μ˜λ„ν•˜μ§€ μ•Šμ€ 잘λͺ»μ„ μ–‘μ‚°ν•˜κΈ° μ‰¬μšΈκ²ƒμ΄λ‹€. κ²Œλ‹€κ°€ μ˜ˆμ™ΈλŠ” unexpected μ˜ˆμ™Έμ—μ„œ λ°œμƒν•˜λŠ” 높은 레벨의 μ˜ˆμ™Έ μž‘λŠ” λ¬Έμ œμ— λŒ€ν•˜μ—¬ μ˜ˆλ°©ν• μˆ˜ μžˆλ‹€.

자 μ΄λŸ°κ²ƒλ“€μ΄ μ˜ˆμ™Έ λͺ…μ„ΈλΌ ν˜„λͺ…ν•˜κ²Œ μ‚¬μš©ν•˜λŠ”λ° 일쑰할 것이닀. λ‹Ήμ‹ μ˜ ν•¨μˆ˜μ— μ˜ˆμ™ΈλΌ λ”ν•˜κΈ° 전에 이런 사항에 λŒ€ν•˜μ—¬ ν•œλ²ˆμ생각해 보자.

1.7. Item 15: Understand the costs of exception handling

  • Item 15: μ˜ˆμ™Έ 핸듀링에 λŒ€ν•œ λΉ„μš© μ§€λΆˆ λŒ€ν•œ 이해

μ‹€ν–‰μ‹œκ°„μ— μ˜ˆμ™Έ 핸듀링을 μœ„ν•˜μ—¬ ν”„λ‘œκ·Έλž˜λ¨ΈλŠ” ν•œμŒμ˜ μ½”λ“œλΌ μž…λ ₯ν•΄μ•Ό ν•œλ‹€. μ˜ˆμ™Έ 쀑에 각자의 ν¬μΈνŠΈμ— ν”„λ‘œκ·Έλž˜λ¨ΈλŠ” 각 tryλΈ”λŸ­μ— λ“€μ–΄κ°€λŠ” λΆ€λΆ„κ³Ό λ‚˜μ˜€λŠ” λΆ€λΆ„λ”°μœ„μ˜ μ˜ˆμ™Έκ°€ λ˜μ €μ§ˆλ•Œ 객체 파괴의 ν•„μš”μ„±μ„ ν™•μΈν•΄μ•Όλ§Œ ν•œλ‹€. 그리고 각 try λΈ”λ‘μ—μ„œ ν”„λ‘œκ·Έλž˜λ¨ΈλŠ” catchꡬ문의 연계와 κ·Έλ“€κ³Ό κ΄€κ³„λ˜μ–΄ μžˆλŠ” μ˜ˆμ™Έ 객체의 μ’…λ₯˜μ— λŒ€ν•˜μ—¬λ„ 생각해 μ£Όμ–΄μ•Ό ν•œλ‹€. 이런 것듀은 κ²°μ½” κ³΅μ§œκ°€ μ•„λ‹ˆλ‹€. μ‹€ν–‰μ‹œκ°„λ™μ•ˆμ— μ˜ˆμ™Έ λͺ…세에 λŒ€ν•œ 확인 μž‘μ—…λ„ 그러며, catchꡬ문에 객체가 던져 μ§”μ„λ•Œ 객체의 파괴 뢀뢄에 λŒ€ν•œ 일도 μ—­μ‹œ ν™•μž₯λœλ‹€. ν•˜μ§€λ§Œ, λ§Œμ•½ 당신이 try, throw, catchν‚€μ›Œλ“œλΌ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ μ˜ˆμ™Έ 핸듀링에해단 λΉ„μš©μ€ λ°œμƒν•˜μ§€ μ•Šκ³ , ν•΄λ‹Ή ν‚€μ›Œλ“œλ“€μ— λŒ€ν•œ λΉ„μš© μ§€λΆˆλ„ λΈλΈν•œ 양이닀.

자 그럼 μ „ν˜€ μ˜ˆμ™Έ 핸듀링을 ν•˜μ§€ μ•Šμ•˜μ„λ•Œμ˜ μ§€λΆˆ λΉ„μš©μ„ 생각해 보자, 당신은 객체듀이 적재되고, μœ μ§€λ˜λŠ” νŠΈλž™μ΄ ν•„μš”ν•œ 데이터 ꡬ쑰의 μ‚¬μš©μ„ μœ„ν•΄ 곡간에 λŒ€ν•œ λΉ„μš© μ§€λΆˆμ„ ν•œλ‹€. 그리고 당신은 이런 데이터 ꡬ쑰듀을 κ°±μ‹ ν•˜κ³  μœ μ§€ν•˜λŠ”λ° ν•„μš”ν•œ μ‹œκ°„μ— λŒ€ν•œ λΉ„μš©μ„ μ§€λΆˆν•œλ‹€. 이런 λΉ„μš©λ“€μ€ 일반적으둜 μ •λ‹Ήν•œ μš”κ΅¬μ΄λ‹€. λ°˜λ©΄μ— ν”„λ‘œκ·Έλž¨μ΄ μ˜ˆμ™ΈλΌ μœ„ν•œ 지원이 없이 컴파일 λœλ‹€λ©΄ μ˜ˆμ™Έ 지원을 ν•˜κ³  컴파일 ν•˜λŠ” λ°˜λŒ€μ˜ κ²½μš°λ³΄λ‹€ μ€λ” λΉ λ₯΄κ³ , μ€λ” μž‘μ€ μš©λŸ‰μ„ μ°¨μ§€ν•œλ‹€.

이둠적으둜 당신은 이런(μ˜ˆμ™Έ) λΉ„μš©μ˜ μ§€μΆœ(선택,select)이 μ—†μ–΄μ•Ό ν•œλ‹€.:C++의 ν•œ 뢀뢄인 μ˜ˆμ™Έ, μ»΄νŒŒμΌλŸ¬λŠ” μ˜ˆμ™ΈλΌ μ§€μ›ν•΄μ•Όν•œλ‹€.

ν”„λ‘œκ·Έλž¨μ€ 일반적으둜 λ…λ¦½μ μœΌλ‘œ object νŒŒμΌλ“€μ΄ μƒμ„±λ˜μ–΄ 지고, 단지 ν•˜λ‚˜μ˜ μž‘μ„±λ˜μ–΄ λ§Œλ“€μ–΄μ§„ objectνŒŒμΌμ—μ„œ μ˜ˆμ™Έ μ²˜λ¦¬κ°€ μ—†λ‹€λ©΄ λ‹€λ₯Έ κ²ƒλ“€μƒμ˜ μ˜ˆμ™Έ μ²˜λ¦¬κ°€ μ•„λ¬΄λŸ° 의λΈκ°€ μ—†κΈ°λ•Œλ¬Έμ—, 당신이 μ˜ˆμ™Έμ²˜λ¦¬μ½”λ“œλΌ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄, 당신은 컴파일러 μ œμž‘μ‚¬λ“€μ΄ 이런 μ˜ˆμ™Έλ“€μ„ μ§€μ›μ‹œ μΌμ–΄λ‚˜λŠ” λΉ„μš©μ„ 없앨 것이라고 μ˜ˆμƒν•œλ‹€. κ²Œλ‹€κ°€ object파일이 μ˜ˆμ™ΈλΌ λΉΌκΈ°μœ„ν•΄ μ•„λ¬΄λŸ° μƒν˜Έκ°„μ˜ 링크가 λ˜μ§€ μ•ŠλŠ”λ‹€λ©΄ μ˜ˆμ™Έ μ²˜λ¦¬κ°€ λ“€μ–΄κ°„ λΌμ΄λΈŒλŸ¬λ¦¬μ™€μ˜ λ§ν¬λŠ” μ–΄λ–¨κΉŒ? 즉, ν”„λ‘œκ·Έλž¨μ˜ μ–΄λ–€ 뢀뢄이라도 μ˜ˆμ™ΈλΌ μ‚¬μš©ν•œλ‹€λ©΄ λ‚˜λ¨Έμ§€ ν”„λ‘œκ·Έλž¨μ˜ 뢀뢄듀도 μ˜ˆμ™ΈλΌ μ§€μ›ν•΄μ•Ό ν•œλ‹€. 이런 뢀뢄적 μ˜ˆμ™Έ 처리 상황은 μ‹€ν–‰μ‹œκ°„μ— μ •ν™•ν•œ μ˜ˆμ™ΈλΌ μž‘λŠ” μˆ˜ν–‰μ΄ λΆˆκ°€λŠ₯ ν•˜κ²Œ λ§Œλ“€κ²ƒμ΄λ‹€.

λ¬Όλ‘  저것은 이둠이닀. μ‹€μ§ˆμ μœΌλ‘œ μ˜ˆμ™Έ 지원 밴더듀은 당신이 μ˜ˆμ™Έ μž‘μ„±μ„ μœ„ν•œ μ½”λ“œμ˜ μ²¨κ°€λΌ λ‹Ήμ‹ μ΄ μ˜ˆμ™ΈλΌ μ§€μ›ν•˜λŠλƒ λ§ˆλŠλƒμ— 따라 μ‘°μ •ν• μˆ˜ μžˆλ„λ‘ λ§Œλ“€μ–΄ λ†“μ•˜λ‹€.(μž‘μ„±μžμ£Ό:즉 μ˜ˆμ™Έ κ΄€λ ¨ 처리의 on, offκ°€ κ°€λŠ₯ν•˜λ‹€.) λ§Œμ•½ 당신이 λ‹Ήμ‹ μ˜ ν”„λ‘œκ·Έλž¨μ˜ μ–΄λ– ν•œ μ˜μ—­κ³Ό, μ—°κ³„λ˜λŠ” λͺ¨λ“  λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ try, throw, catchλΌ λΉΌκ³  μ˜ˆμ™Έ 지원 사항을 λΉΌκ³  λ‹Ήμ‹  슀슀둜 속도, 크기 같은 μ˜ˆμ™Έμ²˜λ¦¬μ‹œ λ°œμƒν•˜λŠ” 단점을 μ œκ±°ν• μˆ˜ μžˆμ„ 것이닀. μ‹œκ°μ΄ μ§€λ‚˜ 감에 따라 λΌμ΄λΈŒλŸ¬λ¦¬μ— μ°¨μš©λ˜λŠ” μ˜ˆμ™Έμ˜ μ²˜λ¦¬λŠ” 점점 λŠ˜μ–΄λ‚˜κ²Œ 되고, μ˜ˆμ™ΈλΌ μ œκ±°ν•˜λŠ” ν”„λ‘œκ·Έλž˜λ°μ€ 갈수둝 내ꡬ성이 μ•½ν•΄ μ§ˆκ²ƒμ΄λ‹€. ν•˜μ§€λ§Œ, μ˜ˆμ™Έμ²˜λ¦¬λΌ λ°°μ œν•œ μ»΄νŒŒμΌμ„ μ§€μ›ν•˜λŠ” ν˜„μž¬μ˜ C++ μ†Œν”„νŠΈμ›¨μ–΄ κ°œλ°œμƒμ˜ μƒνƒœλŠ” ν™•μ‹€νžˆ μ˜ˆμ™Έμ²˜λ¦¬ 보닀 μ„±λŠ₯μ—μ„œ μš°μœ„λΌ μ ν•œλ‹€. 그리고 그것은 λ˜ν•œ μ˜ˆμ™Έ 전달(propagate) μ²˜λ¦¬μ™€, μ˜ˆμ™ΈλΌ μƒκ°ν•˜μ§€ μ•Šμ€ λΌμ΄λΈŒλŸ¬λ¦¬λ“€μ˜ μ‚¬μš©μ— λ¬΄λ¦¬μ—†λŠ” 선택이 될것이닀.

λ‘λ²ˆμ§Έλ‘œ try λΈ”λ‘μœΌλ‘œλΆ€ν„°μ˜ μ˜ˆμ™ΈλΌ μž‘λŠ”(exception-handling)에 λŒ€ν•œ λΉ„μš©μ„ 생각해 보자 이것은 당신이 catch둜 μ˜ˆμ™Έ ν•˜λ‚˜λΌ μž‘κΈ°λΌ μ›ν• λ•Œ λ§ˆλ‹€ μš”κ΅¬λ˜λŠ” λΉ„μš©μ΄λ‹€. 각기 λ‹€λ₯Έ μ»΄νŒŒμΌλŸ¬λ“€μ€ μ„œλ‘œ λ‹€λ₯Έ λ°©μ‹μœΌλ‘œ tryλΈ”λ‘μ˜ μ μš©μ„ ν•œλ‹€. κ·Έλž˜μ„œ ν•΄λ‹Ή λΉ„μš©μ€ 각 μ»΄νŒŒμΌλŸ¬λ§ˆλ‹€ λ‹€λ₯΄λ‹€. κ·Έλƒ₯ λŒ€μΆ© μ–΄λ¦Όμž‘μ•„μ„œ μ˜ˆμƒν•˜λ©΄, λ§Œμ•½ try블둝을 μ“°κ²Œλ˜λ©΄, λ‹Ήμ‹ μ˜ 전체적인 μ½”λ“œ μ‚¬μ΄μ¦ˆλŠ” 5-10%κ°€ λŠ˜μ–΄λ‚˜κ³ , λ‹Ήμ‹ μ˜ μ‹€ν–‰ μ‹œκ°„ μ—­μ‹œ λΉ„μŠ·ν•œ 수μ€μœΌλ‘œ λŠ˜μ–΄λ‚œλ‹€. 이제 μ•„λ¬΄λŸ° μ˜ˆμ™ΈλΌ λ˜μ§€μ§€ μ•ŠλŠ”λ‹€κ³  μƒκ°ν•˜μž;μš°λ¦¬κ°€ μ—¬κΈ°μ—μ„œ ν† λ‘ ν•˜κ³  μžˆλŠ”κ²ƒμ€ 단지 λ‹Ήμ‹ μ˜ ν”„λ‘œκ·Έλž¨λ‚΄μ—μ„œ tryκ°€ κ°€μ§€λŠ” λΉ„μš©λ§Œμ΄ μ•„λ‹ˆλ‹€. 이런 λΉ„μš©μ˜ μ΅œμ†Œν™”λΌ μœ„ν•΄μ„œ μ•„λ§ˆ 당신은 ν•„μš”ν•˜μ§€ μ•ŠλŠ” tryλΈ”λŸ­μ€ ν”Όν•΄μ•Όλ§Œ 할것이닀.

μ»΄νŒŒμΌλŸ¬λŠ” μˆ˜λ§£μ€ try λΈ”λŸ­μ˜ μ˜ˆμ™Έ μŠ€νŽ™μ— λŒ€ν•œ μ½”λ“œλΌ μœ„ν•˜μ—¬ μ½”λ“œλΌ λ§Œλ“€μ–΄λ‚΄μ•Ό ν•œλ‹€. κ·Έλž˜μ„œ μ½”λ“œ μŠ€νŒ©μ€ 일반적으둜 ν•˜λ‚˜μ˜ tryλΈ”λŸ­λ‹Ή 같은 수의 λΉ„μš©μ„ μ§€μΆœν•˜κ²Œ λœλ‹€. 잠깐?(excuse me?) 당신은 μ˜ˆμ™Έ 슀팩이 λ‹¨μ‹œ 슀팩인, 즉 μ½”λ“œλΌ λ§Œλ“€μ–΄ λ‚΄λŠ”κ±Έ μƒκ°ν•˜μ§€ μ•ŠλŠ”λ‹€κ³  λ§ν•œλ‹€. 자, λ‹Ήμ‹œμ€ 그런 생각에 κ΄€ν•΄μ„œ 쑰금 μƒˆλ‘œμš΄ λͺ‡κ°€μ§€λΌ κ°μ•ˆν•΄ 봐ㅏ.

문제의 μ΄ˆμ μ€ μ˜ˆμ™Έκ°€ λ˜μ§€λŠ” λΉ„μš©μ΄λ‹€. 사싀 μ˜ˆμ™ΈλŠ” ν¬κ·€ν•œ 것이라 보기 λ•Œλ¬Έμ— κ·Έλ ‡κ²Œ 크게 κ°μ•ˆν•  λ‚΄μš©μ΄ μ•„λ‹ˆλ‹€. 그듀이 μ˜ˆμ™Έμ μΈ(exceptional) 문제의(event) λ°œμƒμ„ 지칭함에도 λΆˆκ΅¬ν•˜κ³  말이닀. 80-20 κ·œμΉ™μ€(Item 16μ—μ„œ μ–ΈκΈ‰) μš°λ¦¬μ—κ²Œ 그런 μ΄λ²€νŠΈλ“€μ€ 거의 ν”„λ‘œκ·Έλž¨μ˜ λΆ€κ³Όλ˜λŠ” μ„±λŠ₯에 μ»€λ‹€λž€ 영ν–₯을 λΈμΉ˜μ§€ μ•Šμ„ 것이라고 λ§ν•œλ‹€. κ·ΈλŸΌμ—λ„ λΆˆκ΅¬ν•˜κ³ , λ‚˜λŠ” 당신이 이 λ¬Έμ œμ— κ΄€ν•˜μ—¬ μ˜ˆμ™ΈλΌ λ˜μ§€κ³ , λ°›λŠ” λΉ„μš©μ— κ΄€ν•œ λŒ€λ‹΅μ—μ„œ μ–Όλ§ˆλ‚˜ ν΄κΉŒλΌ κΆκΈˆν• κ²ƒμ΄λΌκ³  μƒκ°ν•œλ‹€. λŒ€κ°• 일반적인 ν•¨μˆ˜μ˜ λ°˜ν™˜μ—μ„œ μ˜ˆμ™ΈλΌ λ˜μ§„λ‹€λ©΄ λŒ€μΆ© μ„Έκ°œμ˜ λͺ…λ Ήμ–΄ 정도 더 λŠλ €μ§€λŠ”(three order of magnitude) 것이라고 κ°€μ •ν• μˆ˜ μžˆλ‹€. ν•˜μ§€λ§Œ 당신은 κ·Έκ²ƒλ§Œμ΄ 아닐것이라고 이야기 할것이닀. λ°˜λŒ€λ‘œ 당신이 이런 λ…ΌμŸμ„ 데이터 κ΅¬μ‘°λ‚˜ λ£¨ν”„μ˜ 순회 κ΅¬μ‘°λΌ νš¨μœ¨μ μœΌλ‘œ λ§Œλ“œλŠ”λ° 신경을 μ“΄λ‹€λ©΄ 더 쒋은 μ‹œκ°„μ„ λ³΄λ‚΄λŠ” 것이라고 μƒκ°ν•œλ‹€.

κ·Έλ ‡μ§€λ§Œ 잠깐, λ‚΄κ°€ μ΄λŸ°κ²ƒμ— κ΄€ν•΄μ„œ μ–΄λ–»κ²Œ 아냐ꡬ? λ§Œμ•½ μ˜ˆμ™ΈλΌ μœ„ν•œ 지원은 졜근의 μ»΄νŒŒμΌλŸ¬μ™€ γ„·μ»΄νŒŒμΌλŸ¬κ°„μ— λ‹€λ₯Έ λ°©μ‹μœΌλ‘œ μ§„ν–‰λœλ‹€λ©΄μ„œ λΉ„μš©μ΄ 5-10%떨어지고 μŠ€ν”Όλ“œ μ—­μ‹œ λΉ„μŠ·ν•˜κ²Œ 떨어지고 μ„Έκ°œ λͺ…λ Ήμ–΄ 정도 λŠ˜μ–΄λ‚˜λŠ” 것과 같은 μ„±λŠ₯ μ €ν•˜μ— κ΄€ν•œ μœ„μ˜ μ–ΈκΈ‰ μ΄λŸ°κ²ƒμ— κ΄€ν•œ μΆœμ²˜λ“€? μ•„λ§ˆ λ‚΄κ°€ ν•΄μ„μˆ˜ μžˆλŠ” 닡변은 λ‹€μ†Œ λ†€λž„κ²ƒμ΄λ‹€.:당신이 try블둝과 μ˜ˆμ™Έ μŠ€νŽ™μ„ μ‚¬μš©μ„ ν•„μš”ν•œ 곳만 μ‚¬μš©ν•˜λ„λ‘ μ œν•œν•΄λΌ;그리고 컴파일 해봐라, κ·Έλž˜λ„ μ„계상에 λ¬Έμ œκ°€ μžˆλ‹€λ©΄ 일단 μžμ‹ μ˜ μ„κ³„λΌ λ‹€μ‹œ 그렀보고 생각해 보라, 거기에닀, μ—¬κΈ°μ €κΈ° λ‹€λ₯Έ λ²€λ”λ“€μ˜ 컴파일러둜 컴파일 해봐라 그럼 μ•Œμˆ˜ μžˆλ‹€.

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:23:49
Processing time 0.1374 sec