Kori 2월 20일에 포스트됨 공유하기 2월 20일에 포스트됨 마르코 칸투 (Marco Cantu)의 "Try-Finally Blocks for Protecting Multiple Resources in Delphi" 을 번역했습니다. (원문 작성: 2018년 1월, 최종 번역: 2023년 2월) 델파이 언어는 예외가 발생할 경우 리소스가 적절하게 해제되는 것을 확실하게 할 수 있도록 하는 표준 리소스 할당 패턴을 다른 많은 언어와 공유한다. 여기에서 리소스(resources)란 메모리 오브젝트, 파일, 운영 체제의 오브젝트와 핸들 등등을 의미한다. 델파이에서는 메모리 관리 고려라는 측면에서 , 가비지 컬렉터가 있는 다른 언어에 비해, 리소스 해제와 더 밀접하게 관련된다. 목차 1 오브젝트 1개를 보호하기 2 오브젝트 2개를 보호하기: 코드를 이렇게 작성하면 안된다 3 오브젝트 2개를 보호하기: 3가지 해법 이야기 4 그 중 어느 것을 선택할까? 1 오브젝트 1개를 보호하기 간단한 경우, 대부분 아래와 같은 코드를 작성할 것이다. 리소스를 할당한다 (allocate resource) try 리소스를 사용한다 (use resource) finally 리소스를 해제한다 (free resource) end; 보다 구체적인 예문: A1 := TTest.Create; try A1.DoSomething; finally A1.Free; end; 여기까지는 좋다. 위 코드에서는, 생성자(constructor)가 실행되는 도중에 만약 에러가 발생하는 경우에, 델파이는 일부가 초기화된 오브젝트 (이것은 별도의 주제에서 다루기로 한다)의 파괴자(destructor)를 자동으로 실행할 것이므로 안전하다는 점을 알아두자. 2 오브젝트 2개를 보호하기: 코드를 이렇게 작성하면 안된다 이 글에서 집중하려는 문제는, 만약 리소스 2개를 할당(allocate)하고 폐기(dispose)하고 싶은 경우라면 코드를 어떻게 작성해야 하는 지를 살펴보는 것이다. 선택할 수 있는 여러가지 방법이 있다. 먼저, 그렇게 하면 안되는 (하지만, 주변에서 상당히 흔하게 보이는) 코드는 다음과 같다. A1 := TTest.Create; A2 := TTest.Create; try A1.DoSomething; A2.DoSomething (A1); finally A2.Free; A1.Free; end; 위 코드는 만약 A2를 생성하는 코드가 실패하는 (많은 이유가 있을 수 있다) 경우에는, A1 오브젝트가 메모리에 남아있게 된다. 그렇다고 해서 2번째 오브젝트를 생성하는 코드를 아래와 같이 try 블록 안으로 옮기는 것 역시 좋지 않다. A1 := TTest.Create; try A2 := TTest.Create; A1.DoSomething; A2.DoSomething (a); finally A2.Free; A1.Free; end; 위 코드는 만약 A2 오브젝트의 생성자(constructor)가 호출되는 중에 실패하는 경우에는, 초기화되지 않는 오브젝트(로컬 오브젝트 참조 값은 기본이 undefinde 즉 정의되지 않음이다)를 Free 하려는 시도를 finally 블록 안에서 하게 된다 . 해법을 보자. 위 코드에서 A2 변수를 nil로 지정하고, A2 오브젝트의 리소스 생성 코드는 try 블록 안에서 넣는 방법이 있다 - finally 블록 안 있는 Free 코드가 실행될텐데, 이때 nil인 오브젝트에서 호출하는 Free는 아무런 효력이 없기 때문이다. 또는 A2 뿐만아니라 모든 오브젝트 참조를 nil로 지정할 수 있다. 그러면 단순하고 통일성을 유지할 수 있다. 또는 try 블록을 중첩하여 리소스를 각각 보호할 수도 있다. 3 오브젝트 2개를 보호하기: 3가지 해법 이야기 앞에 길게 이야기한 내용을 바탕으로 이 글의 요점으로 가보자. 방금 언급한 것처럼 하나의 코드 블록에서 사용되는 리소스 2개를 모두 보호하는 문제에 대한 해법은 적어도 3가지이다. 아래 그림은 RAD Studio R&D 아키텍트 중 한 명인 Bruneau Babet가 정리한 3가지 해법 그림을 가져온 것이다. 어떠한 경우에도 리소스를 올바르게 보호한다는 측면에서 이 3개 해법 모두 옳다. 그러면 이 3가지 해법 각각의 장점과 단점은 무엇일까? 이 예문에서는 보호해야 할 리소스가 2개 이지만, 그 이상 즉 3개, 4개 또는 10개가 넘는 경우도 고려해야 한다는 점이 중요하다. 4 그 중 어느 것을 선택할까? 첫 번째 해법은 try 블록을 중첩해 사용한다. 상당히 정돈되어 있지만 보다 더 장황하다(코드 줄이 더 많다). 보호해야 할 리소스가 더 많아지면 중첩도 더 많아지므로 짜증이 날 수 있다. 또한 try 블록을 처리하기 위한 런타임 비용 있다는 점도 약점이다. try 블록 처리 비용이 비록 작고 제한인 것은 분명하지만 그렇다고 해서 0은 아니다. 두 번째 해법은 코드 줄이 가장 적고 런타임 비용도 가장 적다. A2를 nil로 지정하는 코드만 추가하면 되기 때문이다. 보호해야 할 리소스가 많아져도 코드를 읽을 수 있다. 그러나 코드의 "균형이 맞지 않고" 이해하기에 다소 혼란스러울 수 있다. 세 번째 해법은 접근 방식이 두번째 해법과 같긴 하지만, (A1에) 기술적으로 쓸모없는 nil을 할당하는 코드를 추가했다. 그 결과 코드는 더 깨끗하고 균형이 잡힌다. 결국 더 읽기 쉬운 코드가 된다. 그래서 가장 좋은 해법은 무엇일까? 이것은 정말 말하기 어렵다. 나는 개인적으로 내 책에서 주로 #1을 사용했지만, Embarcadero는 라이브러리를 작성할 때 더 깨끗하고 빠른 코드(즉, #2 또는 #3)를 선호하는 경향이 있다. 물론 여러분의 의견은 무엇인지에 대해서도 관심이 있다. 인용하기 이 댓글 링크 다른 사이트에 공유하기 더 많은 공유 선택 사항
Recommended Posts
이 토의에 참여하세요
지금 바로 의견을 남길 수 있습니다. 그리고 나서 가입해도 됩니다. 이미 회원이라면, 지금 로그인하고 본인 계정으로 의견을 남기세요.