보통 대부분의 프로그래머들의 코드를 보면
객체 생성시 항상 성공할 것이라는 것을 전제로 하고 있습니다.
물론 생성자에서 성공적인 처리가 안된 경우 실패의 처리 코드를 인자를 통해 되돌려줄 수는 있지만
객체 생성 그 자체가 실패한다는 가정은 안하죠.
class T
{
char buf[10];
public:
T(char *data, int& ret)
{
if (strlen(len > 10)) ret = 1;
strcpy(buf, data);
ret = 0;
}
};
식으로 클래스를 만들었다면
{
int ret;
T *t = new T("긴 스트링.....................", ret);
if (ret)
; // 객체 생성자에서 에러 상황 발생 경우
}
식으로 생성자에서의 인자식으로 리턴값을 설정해 에러 상황를 검사할 수 있다는 뜻 입니다.
이렇게 되면 생성자에서 에러 상황이 발생하던지 말던지 간에
객체 변수 *t 는 메모리에 이미 할당된 클래스 T의 인스턴스를 가르키고 있습니다.
C++ 이나 델파이에서는
생성자 자체가 실패해서 객체 생성 자체가 되지 않을 수도 있습니다.
즉 객체 생성 자체가 실패하면
객체 변수 *t 는 값이 전혀 할당되지 않습니다. *t 객체 변수는 그냥 이전에 가지고 있던 그 값이 그대로 유지 됩니다.
그러면 생성자에서 클래스의 인스턴스 생성 실패는 어떻게 구현할까요?
생성자는 그 구조가 함수와 같은 방식의 단일한 리턴 값을 가지지 못하는 구조입니다.
그리고 메모리에 객체의 인스턴스를 생성할지 말지 여부는 컴파일러의 처리에 맡기게 되어 있으므로,
생성를 실패시키는 방법은 강제로 생성자가 끝까지 실행되지 않게 중간에 예외를 일으키는 방법을 쓰면 됩니다.
//---------------------------------------------------------------------------
class T
{
char buf[100];
public:
T()
{
throw 1;
}
};
테스트를 위해 이와 같이 강제로 생성자에서 예외를 일으킵니다.
void __fastcall TForm1::Button3Click(TObject *Sender)
{
T *t = NULL;
try
{
t = new T;
}
__finally
{
delete t;
}
}
//---------------------------------------------------------------------------
그러면 결과적으로
t 는 NULL 값을 그대로 유지하게 됩니다.
그리고 delete t; 는 결국 0 번지를 delete 하게 되므로 delete 동작 자체가 취소되게 됩니다.
위와 같이 throw 나 Exception을 통한 예외 발생 뿐만 아니라,
메모리가 부족해서 객체를 할당할 수 없는 경우도 마찬가지의 경우가 생깁니다.
그러므로, 위와 같이 객체를 다루는 것이 가장 안전한 방법의 구조를 보여주는 것입니다.
상용 프로그램을 만든다면 이렇게 완전하게 객체 생성 실패의 경우까지 대비하는 것이 옳아 보입니다.
하지만 이는 코딩시 귀잖은 요소이고, 현실적으로 무시해도 좋다고 판단됩니다.
물론 경우에 따라서 try 블럭으로 반드시 객체 생성의 실패에 대비해야 하는 경우도 있으나,
대부분의 경우는 객체 생성 실패의 가능성이 지극히 적어 고려하지 않아도 그다지 지장이 없습니다.
특수한 경우에 대한 대비, 가령 대용량의 메모리 할당 등의 실패와 같은 경우는
객체 생성의 실패를 반드시 점검해야 합니다.
이는 new 로 인스턴스의 메모리를 할당 받아 쓰는 모든 경우에 동일한 사항입니다.
이러한 사항은 한번 주지할 필요가 있는 이유는,
생성자에서 만일 어떤 기능을 구현해야 하는데
그 기능 구현을 위해 호출하는 다른 클래스의 메소드나 객체 생성등에서
예외가 나서 자신이 구현한 클래스의 생성자가 완결되지 못하는 경우가 생기기 때문입니다.
자신의 코드만 이상 없으면 되는 일이 아니라는 것이죠.
그러므로
자신이 코딩한 생성자에서 다른 객체를 생성한다던지,
또는 자신이 분명하게 모르는 어떤 객체나 함수의 기능을 쓸때 예외가 일어날 가능성에 대해
try 블럭을 써서 예외를 잡아 내는 식으로 분명하게 대비해야 한다는 것입니다.
그렇지 않으면 자신이 코딩하지 않은 부분의 예외로 인해
자신이 코딩한 클래스의 인스턴스 자체가 메모리에 만들어지지 않는 상황이 발생할 수도 있기 때문입니다.
그닥 대단한 내용은 아니지만 한번 알아둘 필요가 있는 내용이었습니다.
빌더 쓰시는 분들은 오래 코딩하신 분들이 많아 대부분 아실 것군요.
그럼..
|
-- 생성자 자체가 실패해서 객체 생성 자체가 되지 않을 수도 있습니다
...
-- 그러면 생성자에서 클래스의 인스턴스 생성 실패는 어떻게 구현할까요?
-- 생성자는 그 구조가 함수와 같은 방식의 단일한 리턴 값을 가지지 못하는 구조입니다.
-- 그리고 메모리에 객체의 인스턴스를 생성할지 말지 여부는 컴파일러의 처리에 맡기게 되어 있으므로,
-- 생성를 실패시키는 방법은 강제로 생성자가 끝까지 실행되지 않게 중간에 예외를 일으키는 방법을 쓰면 됩니다
C++ 과 델파이를 같이 거론하시는 거보니 new 로 객체를 만드는 것을 얘기하시는 것 같습니다.
C++ 의 경우 new 가 메모리 할당에 실패할 경우에 null 을 반환하는 것이 아니고,
예외를 던지는 것이 C++ 사양입니다. 그렇다면 C++ builder 에서는 new 로 객체를 못만들때,
예외를 던지지 않고 있나요? 문득 궁금해집니다.