E D R S I H C RSS
ID
Password
Join
ë‚˜ì˜ ê²½ê¸°ëŠ” ìž ì—서 깨어난 순간부터 시작ëœë‹¤. --Reggie Jackson


Contents

1 시작하기 ì „ì— ì£¼ì˜ì‚¬í•­
2 개요
3 잡히지 ì•Šì€ ì˜ˆì™¸ì— ëŒ€í•œ 처리
4 표준 ì˜ˆì™¸ì˜ í™œìš©
5 í™œìš©ìš©ë„ ë° ì •ë¦¬

1 시작하기 ì „ì— ì£¼ì˜ì‚¬í•­ #


ì´ ê°•ì¢Œì—서 설명하는 예외처리는 ANSI C++ í‘œì¤€ì— ì˜í•´ ì œì‹œëœ ê³µì¸ëœ 새로운 í‘œì¤€ì— ëŒ€í•œ ë‚´ìš©ì´ë‹¤. 만약 ì´ í‘œì¤€ì„ ì œê³µí•˜ì§€ 않는 컴파ì¼ëŸ¬ë¥¼ 사용한다면, ì´ ê¸°ëŠ¥ì„ ì‹¤ìŠµí•  수 ì—†ìŒì„ ë°ížŒë‹¤. ì¼ë°˜ì ìœ¼ë¡œ 컴파ì¼ëŸ¬ ìžì²´ì˜ 예외처리 ë¬¸ë²•ì„ ê°€ì§€ê³  있는 경우가 ë§Žê³ , ê·¸ê²ƒì„ ì‚¬ìš©í•˜ëŠ” ê²ƒì´ ë” ì¢‹ì„ ìˆ˜ 있다. Visual C++ì´ë‚˜ C++ Builder와 ê°™ì€ ìƒì—…ì ìœ¼ë¡œ 유명한 개발툴들과 g++ê³¼ ê°™ì€ íˆ´ì€ í‘œì¤€ 예외처리를 제공한다.

2 개요 #

í”„ë¡œê·¸ëž¨ì„ ê°œë°œí•˜ëŠ” 중ì—는, 제대로 실행ë˜ê³  있는 코드ì¸ì§€ë¥¼ 확신할 수 없는 경우, ë˜ëŠ” 존재하지 않는 ìžì›ì„ 억세스하려한다거나, 지정한 범위를 넘어서서 처리ë˜ëŠ” 경우등등과 ê°™ì€ ì¼ë“¤ì´ ìƒê¸¸ 수 있다.

ì´ëŸ° í˜•íƒœì˜ ë¹„ì •ìƒì ì¸ ìƒí™©ë•Œë¬¸ì— 예외처리를 사용하는 것ì´ë‹¤. C++ì€ ì´ëŸ° ìƒí™©ì— 대처하기 위해 3ê°€ì§€ì˜ ìƒˆë¡œìš´ ì—°ì‚°ìž(try, throw, catch)를 제공한다.

ì´ ì—°ì‚°ìžì˜ 대략ì ì¸ 형태는 다ìŒê³¼ 같다.:
try {
  // 예외가 ë°œìƒí•  ì§€ 모르는 코드 부분
  throw exception; // 예외가 ë°œìƒë˜ì–´ì•¼ í•  경우 예외발ìƒ
}
catch (type exception)
{
  // ê°ê°ì˜ ì˜ˆì™¸ì— ë”°ë¼ ì‹¤í–‰ë˜ì–´ì•¼ 하는 코드들
}

ê°ê°ì˜ ì—­í•  ë° ë™ìž‘ì€ ë‹¤ìŒê³¼ 같다:
  • try ë¸”ëŸ­ë‚´ì˜ ì½”ë“œëŠ” ì •ìƒì ìœ¼ë¡œ 실행ëœë‹¤. ë§Œì¼ ì§€ì •í•œ 블럭내ì—서 예외를 ë°œìƒí•´ì•¼ í•  경우, throw 키워드를 사용한다. throw í‚¤ì›Œë“œì— ë”°ë¥¸ ì¸ìžëŠ” ì–´ë–¤ ê²½ìš°ì— ëŒ€í•œ 예외ì¸ê°€ë¥¼ 나타낸다.
  • 만약 예외가 ë°œìƒí•˜ê±°ë‚˜ throw 키워드가 실행ë˜ë©´, catch ë¸”ëŸ­ì´ ë°œìƒí•œ 예외를 나타내는 ì¸ìžì™€ 함께 실행ë˜ê²Œ ëœë‹¤.

예를 들ìžë©´ 다ìŒê³¼ 같다.:

// exceptions
#include <iostream.h>

int main () {
  char myarray[10];
  try
  {
    for (int n=0; n<=10; n++)
    {
      if (n>9) throw "범위를 벗어남!";
      myarray[n]='z';
    }
  }
  catch (char * str)
  {
    cout << "ì˜ˆì™¸ë°œìƒ : " << str << endl;
  }
  return 0;
}

ì´ ì˜ˆì œëŠ” for 루프안ì—서 nì´ 9ì´ìƒì´ ë˜ë©´ 예외가 throw하ë„ë¡ ìž‘ì„±ë˜ì–´ìžˆë‹¤. (왜ëƒí•˜ë©´, myarrayê°€ 10ê°œì˜ ì¸ìžë¥¼ 가진 배열로 ì„ ì–¸ë˜ì–´ìžˆìœ¼ë¯€ë¡œ ì¸ë±ìŠ¤ê°€ 9ì´ˆê³¼ì¸ ìˆ˜ê°€ 지정ë˜ë©´ ì ê·¼í•  수없는 메모리를 억세스 하는 ê²ƒì´ ë˜ê¸° 때문ì´ë‹¤.) throwê°€ 실행ë˜ë©´ 루프와는 ìƒê´€ì—†ì´ catch ë¸”ëŸ­ë‚´ì˜ ì½”ë“œê°€ 실행ëœë‹¤. 그리고 catch 블럭 아래가 실행ë˜ê¸° 시작한다. (여기서는 그냥 0ì„ ë°˜í™˜í•œë‹¤.

throwì— ì˜í•´ ì‚¬ìš©ëœ ë¬¸ë²•ì€ ë§ˆì¹˜ return 키워드와 비슷하다. 단지 ( ) ë‚´ì— ë“¤ì–´ê°ˆ 수 있는 í˜•íƒœì˜ í•œê°œì˜ ê°’ë§Œì„ ì§€ì •í•  수 있다는 것만 기억해ë‘ìž.

catch ë¸”ëŸ­ì€ ë°˜ë“œì‹œ try ë¸”ëŸ­ì— ì¸ì ‘해서 ì„ ì–¸ë˜ì–´ì•¼ë§Œ 한다. (둘 사ì´ì— 코드가 삽입ë˜ë©´ 안ëœë‹¤) catch ë¬¸ì´ ë°›ì•„ë“¤ì¼ ìˆ˜ 있는 ì¸ìžëŠ” ì–´ë–¤ ì ë²•한 íƒ€ìž…ë„ ìƒê´€ì—†ë‹¤. 여러 개를 지정할 때ì—는 catch는 서로 다른 íƒ€ìž…ì˜ ì¸ìžë¡œì„œ ì¤‘ì²©ì„ ì–¸ë  ìˆ˜ 있다. ì´ëŸ° 경우는 try 블럭내ì—서 해당 throw íƒ€ìž…ì— ë§žëŠ” catch 블럭만 실행ëœë‹¤:

// 예외처리 : 다중 catch 블럭
#include <iostream.h>

int main () {
  try
  {
    char * mystring;
    mystring = new char [10];
    if (mystring == NULL) throw "할당 실패!";
    for (int n=0; n<=100; n++)
    {
      if (n>9) throw n;
      mystring[n]='z';
    }
  }
  catch (int i) // 예외 1
  {
    cout << "예외 1 : ";
    cout << "ì¸ë±ìФ " << i << " ë²ˆì€ ë²”ìœ„ë¥¼ 벗어난 것임!" << endl;
  }
  catch (char * str) // 예외 2
  {
    cout << "예외 2 : " << str << endl;
  }
  return 0;
}

위 코드와 ê°™ì€ ê²½ìš°ëŠ” ì ì–´ë„ 2ê°€ì§€ì˜ ì˜ˆì™¸ê°€ ë°œìƒí•  ê°€ëŠ¥ì„±ì´ ìžˆë‹¤:

  1. 10ê°œì˜ ë¬¸ìžì— 대한 메모리가 할당ë˜ì§€ ì•Šì•˜ì„ ê²½ìš°(ê±°ì˜ ì¼ì–´ë‚˜ê¸° 힘들지만, ê°€ëŠ¥ì€ í•˜ë‹¤) : 예외 2ë²ˆì´ ë°œìƒí•œë‹¤.
  2. mystringì˜ ì¸ë±ìФ ì§€ì •ì´ ìµœëŒ€ì¹˜(9)를 ë„˜ì—ˆì„ ê²½ìš° : 예외 1ë²ˆì´ ë°œìƒí•œë‹¤.

ë˜í•œ catch ë¸”ëŸ­ì´ throw로 ë˜ì ¸ì§€ëŠ” 특정 예외 íƒ€ìž…ì— ì¢…ì†ë˜ì§€ 않고, 모든 예외를 수용할 수 있ë„ë¡ ì •ì˜í•  수 있다. (ì²˜ìŒ ë¬¸ë²•ì„ ë³´ë©´ ì˜ì•„í•´í•  ìˆ˜ë„ ìžˆì§€ë§Œ, ^^) ì¸ìž 대신 ...ì´ë¼ê³  넣으면 ëœë‹¤:

try {
  // 실행코드부분
}
catch (...) {
  cout << "무언지 모르지만, 예외발ìƒ!";
}

It is also possible to nest try-catch blocks within more external try blocks. In these cases, we have the possibility that an internal catch block forwards the exception received to the external level, for that it is used the expression throw; with no arguments. For example:

try {
  try {
      // 실행코드부분
  }
  catch (int n) {
      throw;
  }
}
catch (...) {
  cout << "예외발ìƒ!";
}

3 잡히지 ì•Šì€ ì˜ˆì™¸ì— ëŒ€í•œ 처리 #

만약 맞는 catch íƒ€ìž…ì´ ì—†ì–´ì„œ 지정한 catch ë¬¸ìž¥ë“¤ì— ëŒ€í•´ 예외가 잡히지 않았다면, 특별한 terminateë¼ëŠ” 함수가 실행ëœë‹¤. ì´ í•¨ìˆ˜ëŠ” ì¼ë°˜ì ìœ¼ë¡œ 현재 프로세스를 종료하고, "Abnormal Termination"ì—러를 출력한다. ê·¸ 함수 ì •ì˜ëŠ” 다ìŒê³¼ 같다:
void terminate();

4 표준 ì˜ˆì™¸ì˜ í™œìš© #

Some functions of the standard C++ language library send exceptions that can be captured if we include them within a try block. These exceptions are sent with a class derived from std::exception as type. This class (std::exception) is defined in the C++ standard header file <exception> and serves as pattern for the standard hierarchy of exceptions:

exception
  • bad_alloc (thrown by new)
  • bad_cast (thrown by dynamic_cast when fails with a referenced type)
  • bad_exception (thrown when an exception doesn't match any catch)
  • bad_typeid (thrown by typeid)
  • logic_error
    • domain_error
    • invalid_argument
    • length_error
    • out_of_range
  • runtime_error
    • overflow_error
    • range_error
    • underflow_error
ios_base::failure (thrown by ios::clear)

Because this is a class hierarchy, if you include a catch block to capture any of the exceptions of this hierarchy using the argument by reference (i.e. adding an ampersand & after the type) you will also capture all the derived ones (rules of inheritance in C++).

The following example catches an exception of type bad_typeid (derived from exception) that is generated when requesting information about the type pointed by a null pointer:

// standard exceptions

#include <iostream.h>
#include <exception>
#include <typeinfo>

class A {virtual f() {}; };

int main () {
  try {
    A * a = NULL;
    typeid (*a);
  }
  catch (std::exception& e)
  {
    cout << "Exception: " << e.what();
  }
  return 0;
}

ì˜ˆì™¸ì— ëŒ€í•œ 표준 ìƒì† í´ëž˜ìŠ¤ë“¤ì„ ì‚¬ìš©í•  수 ìžˆì„ ê²ƒì´ë‹¤. ì´ë ‡ê²Œ í•¨ìœ¼ë¡œì¨ ê°œë°œìžë§Œì˜ 예외를 ë˜ì§ˆ 수 있다ë˜ê°€, 새로운 예외ìƒí™©ì„ ìƒì†ë°›ì•„ 만들 수 있게 ëœë‹¤.

5 í™œìš©ìš©ë„ ë° ì •ë¦¬ #

예외는 C++ì˜ ê°•ë ¥í•œ 기능 중 하나ì´ê³ , 디버깅ì´ë‚˜ 다운ë˜ì§€ 않는 ë°©ì–´ì ì¸ í”„ë¡œê·¸ëž¨ì„ ì œìž‘í•  ë•Œì— ìƒë‹¹ížˆ 강력한 ì—­í• ì„ ìˆ˜í–‰í•  수 있다. 하지만, ê°œì¸ì ìœ¼ë¡œëŠ” ìžì£¼ ì“°ì§€ ì•ŠëŠ”ë° ê·¸ ì´ìœ ëŠ” 다ìŒê³¼ 같다. (주관ì ì¸ ê²ƒìž„ì„ ë°ížŒë‹¤.)

  1. ë°©ì–´ì ì¸ 코드ë¼ê¸° 보다는 ì—러가 잠재ë˜ì–´ìžˆëŠ” 코드를 뒷처리하는 ê²½ìš°ì— ì‚¬ìš©ë˜ëŠ” ê²ƒì´ ë³´í†µì´ì§€ë§Œ, ì´ëŸ° 경우 ê·¸ ì—러를 완벽하게 뒤처리 못하는 경우가 많다. 심지어 그냥 í”„ë¡œê·¸ëž¨ì„ ë¦¬ì…‹í•  경우가 ë§Žì€ë°, ì´ëŸ´ë•ŒëŠ” ì°¨ë¼ë¦¬ assertê°€ ë” íŽ¸ë¦¬í•˜ë‹¤.
  2. í”„ë¡œê·¸ëž¨ì„ ëª¨ë“ˆí™”í•˜ê¸° 힘들게 ëœë‹¤. 예외란 ê²ƒì€ ì–¸ì œë‚˜ ì¼ì • 코드ì˜ì—­ì„ 싸고 있는 형태를 취하므로, 특정 í´ëž˜ìŠ¤ë“¤ì˜ ë§´ë²„í•¨ìˆ˜ë“¤ì— ê±¸ì³ì„œ ì¼ì–´ë‚˜ëŠ” ë²„ê·¸ê°™ì€ ê²ƒì—는 대처하기가 ìƒë‹¹ížˆ 어렵다.
  3. ì½”ë“œëŸ‰ì´ ëŠ˜ì–´ë‚œë‹¤. (ë”°ë¼ì„œ 귀찮다. ^^) 게다가 ë‚˜ì¤‘ì— ì¼ì‹œì ì¸ 버그로 ë°í˜€ì¡Œì„ 때ì—는 쉽게 ê³ ì¹  수 없다. (catchë¶€ë¶„ì˜ ì½”ë“œê°€ 아까워질 수 있다. -_-;)
  4. ë‚´ë¶€ì ìœ¼ë¡œ 스íƒì„ 사용하므로 너무 중첩ì ìœ¼ë¡œ 사용하면 곤란하다.
  5. 여러 예외가 중첩ì ìœ¼ë¡œ ì¼ì–´ë‚  경우(tryë‚´ë¶€ì— ë˜ try...ì´ëŸ° ì‹ì¼ 경우) 잘못 작성하면 ì–´ëŠ ì˜ˆì™¸ê°€ ë°œìƒí–ˆëŠ”ì§€ì¡°ì°¨ 헛갈릴 수 있다. 다시ë§í•˜ë©´, 중급ì´ìƒì˜ 활용ì—서는 ì•½ê°„ì˜ íŠ¸ë¦­ì´ í•„ìš”í•˜ë‹¤. (위 "표준 ì˜ˆì™¸ì˜ í™œìš©" 참조)

ì´ì œëŠ” 사용하면 ê´œì°®ì€ ê²½ìš°ë¥¼ 들어보겠다. (역시 주관ì . ^^)

  1. 특정 소스ë¼ì¸ì´ 아닌 블럭내ì—서 프로그램 ì‹¤í–‰ì´ ë©ˆì¶œì •ë„ì˜ ì—러가 ë°œìƒí•  ê°€ëŠ¥ì„±ì´ ìžˆì§€ë§Œ, í”„ë¡œê·¸ëž¨ì´ ê³„ì† ì‹¤í–‰ë˜ì–´ì•¼ë§Œ í•  경우를 들 수 있다. (0으로 나눌경우가 대표ì ì¸ 예ì´ë‹¤. ì´ë•Œì—는 1로만 ë°”ê¾¸ì–´ì¤˜ë„ ê·¹ë³µì´ ê°€ëŠ¥í•˜ë‹¤.)
  2. 특정 ë¼ì´ë¸ŒëŸ¬ë¦¬ëŠ” 아예 ë‚´ë¶€ì ìœ¼ë¡œ 예외를 정해서 ì—러가 ë°œìƒí•˜ë©´ ê·¸ì— ë”°ë¥¸ 예외를 실행하ë„ë¡ ë˜ì–´ìžˆëŠ” 경우가 있다. (ACEê°€ 대표ì ì¸ 예ì´ë‹¤) ì´ë•Œì—는 예외를 공부해ë‘는 ê²ƒì´ ì¢‹ë‹¤.
  3. ìžì‹ ë§Œì˜ ë¼ì´ë¸ŒëŸ¬ë¦¬ë¥¼ 제작할 경우, 표준 예외를 ìƒì†í•´ì„œ 몇가지 예외를 선언해ë‘ê³  활용하면 ë¼ì´ë¸ŒëŸ¬ë¦¬ë¥¼ 사용하는 쪽ì—서 편리할 수 있다. 예외를 í´ëž˜ìŠ¤ë¡œ 줄 수 있다는 ê²ƒì€ ìƒë‹¹ížˆ 강력한 ê°œë…ì´ë¯€ë¡œ 확실히 알아ë‘는 ê²ƒì´ ì¢‹ë‹¤.

특히 중요한 ê²ƒì€ catch ë¶€ë¶„ì— ê°œë°œ ì¤‘ì¸ ì¤‘ìš”í•œ 처리 코드를 넣는 ê²ƒì€ ê°€ê¸‰ì  í•˜ì§€ 않는 ê²ƒì´ ì¢‹ë‹¤. ì˜ˆì™¸ì²˜ë¦¬ë„ ë””ë²„ê·¸ìš©ì´ë¯€ë¡œ 버그가 없다고 íŒë‹¨ë˜ë©´ 지우게 ë˜ëŠ” 코드ë¼ëŠ” ì ì„ 명심하기 바란다. 그리고 ì¼ì‹œì ì´ê³  복구가 힘든 ì—러(ë¶ˆí–‰ížˆë„ ì´ëŸ° 경우가 대부분ì´ë‹¤)는 assert를 사용하는 ê²ƒì´ íŽ¸ë¦¬í•˜ë‹¤ë¼ëŠ” ê²ƒì„ ì•Œì•„ë‘기 바란다.

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2010-10-28 12:42:52
Processing time 0.3750 sec