2010-01-19 12 views
7

제도에서 자원 획득을 초기화하는 것이 있습니까?RAII에서 Scheme?

GCII 언어에서는 RAII가 잘 작동하지 않는다는 것을 알고 있습니다. (객체가 파괴되었다는 것을 알지 못하기 때문에). 그러나 Scheme에는 연속체, 동적 바람 및 클로저와 같은 유용한 요소가 있습니다.이 조합을 사용하여 RAII를 구현하는 방법이 있습니까?

그렇다면 스키마가 RAII를 사용하지 않도록 코드를 설계하는 방법은 무엇입니까?

는 [I가로 실행하는 일반적인 예는 다음과 같다 : 나는 3D 메쉬를

, 나는 버텍스 버퍼 오브젝트가에 atached있는 메쉬가 더 이상 사용하는 경우, , 나는 VBO가 해제 싶지 .]

고마워!

+0

안녕하세요. 내 대답이 너를 만족 시키면, 아니면 네가 뭔가를 찾고 있다면 궁금해. –

+0

당신의 반응은 그것의 계획이 주어진만큼 좋다고 생각합니다. 우리는 어느 정도 수준에서 모델이 "죽을 때"를 알고 vbo를 포기해야합니다. 그러나 RAII + GC에서는 사전에이를 알 필요가 없습니다. "모델, 내가 언제 죽을 지 모르겠지만, 당신이 할 때 VBO를 포기할 것입니다. ". 스키마가 gc-ed이기 때문에 나중에 할 수 없습니다. 내가 원래 원했던 것은 ... RAII + Refcounting 유형을 제공하는 ref-counting의 일부 유형을 자동으로 인터리브하는 영리한 매크로 맥의 일종이었습니다. – anon

+0

더 추가하려면 다음과 같은 상황을 고려하십시오. 우리는 모델을 생성하고 삭제 된 시점을 알 수는 없지만 많이 렌더링되었음을 알 수 있습니다. VBO를 제공합니다. 그것을 주변에 전달하십시오; ... 아무도 사용하지 않으면 VBO가 해제됩니다. 코드에서 "이제 모델을 무료로 사용할 수 있습니다."라는 단 한 곳도 없습니다. – anon

답변

14

이 단지 일회성 인 경우, 당신은 항상 다만 이전과 썽크 후 설치 및 해체 (나는 allocate-vertex-buffer-objectfree-vertex-buffer-object는 생성자와 소멸자 있다고 믿고있어을하고, 주위 dynamic-wind을 래핑하는 매크로를 쓸 수 여기에) :

(define-syntax with-vertex-buffer-object 
    (syntax-rules() 
    ((_ (name arg ...) body ...) 
    (let ((name #f)) 
     (dynamic-wind 
     (lambda() (set! name (allocate-vertex-buffer-object args ...))) 
     (lambda() body ...) 
     (lambda() (free-vertex-buffer-object name) (set! name #f))))))) 

이 당신이 서로 다른 유형의 개체에 대해 많이 사용하는 패턴을 경우, 매크로의 종류를 생성하는 매크로를 작성할 수 있습니다; 한 번에 일련의 일련 번호를 할당하려고 할 가능성이 높으므로 첫 번째 바인딩 목록이 아닌 단일 바인딩 목록 만 바인딩 목록으로 만들 수 있습니다.

여기에 더 일반적인 버전이 있습니다. 나는 이름 정말 잘 모르겠지만, 그것은 (원래 버전에 무한 루프를 해결하기 위해 편집 ) 기본 개념을 보여줍니다

(define-syntax with-managed-objects 
    (syntax-rules() 
    ((_ ((name constructor destructor)) body ...) 
    (let ((name #f)) 
     (dynamic-wind 
     (lambda() (set! name constructor)) 
     (lambda() body ...) 
     (lambda() destructor (set! name #f))))) 
    ((_ ((name constructor destructor) rest ...) 
     body ...) 
    (with-managed-objects ((name constructor destructor)) 
     (with-managed-objects (rest ...) 
     body ...))) 
    ((_() body ...) 
    (begin body ...)))) 

다음과 같이이를 사용합니다 :

(with-managed-objects ((vbo (allocate-vertex-buffer-object 1 2 3) 
          (free-vertext-buffer-object vbo)) 
         (frob (create-frobnozzle 'foo 'bar) 
          (destroy-frobnozzle frob))) 
    ;; do stuff ... 
) 

다음은 지속성을 사용하여 스코프를 빠져 나갔다가 다시 시작하는 것을 포함하여 작동하는 것을 보여주는 예입니다 (다소 힘든 예입니다.).

(let ((inner-continuation #f)) 
    (if (with-managed-objects ((foo (begin (display "entering foo\n") 1) 
            (display "exiting foo\n")) 
          (bar (begin (display "entering bar\n") (+ foo 1)) 
            (display "exiting bar\n"))) 
     (display "inside\n") 
     (display "foo: ") (display foo) (newline) 
     (display "bar: ") (display bar) (newline) 
     (call/cc (lambda (inside) (set! inner-continuation inside) #t))) 
    (begin (display "* Let's try that again!\n") 
      (inner-continuation #f)) 
    (display "* All done\n"))) 

이 인쇄해야합니다 :

 
entering foo 
entering bar 
inside 
foo: 1 
bar: 2 
exiting bar 
exiting foo 
* Let's try that again! 
entering foo 
entering bar 
exiting bar 
exiting foo 
* All done 

call/cc

단순히 call-with-current-continuation의 약자입니다; 당신의 계획이 더 짧은 것을 가지고 있지 않다면 더 긴 형태를 사용하십시오.

업데이트 : 사용자 의견에서 명확하게 설명했듯이 특정 동적 컨텍스트에서 반환 될 수있는 리소스를 관리하는 방법을 찾고 있습니다. 이 경우 finalizer를 사용해야합니다. 파이널 라이저는 일단 GC가 다른 곳에서 도달 할 수 없다는 것을 증명하면 객체와 함께 호출 될 함수입니다. 파이널 라이저는 표준이 아니지만, 대부분 성숙한 체계 체계에는 때로는 다른 이름으로 사용됩니다. 예를 들어, PLT 체계에서 Wills and Executors을 참조하십시오.

스키마에서 동적 컨텍스트를 다시 입력 할 수 있다는 점에 유의해야합니다. 이것은 예외를 사용하여 임의의 지점에서 동적 컨텍스트를 종료 할 수있는 대부분의 다른 언어와 다르지만 다시 입력 할 수는 없습니다.위 예제에서 dynamic-wind을 사용하여 동적 컨텍스트를 떠날 때 리소스를 할당 해제하고 다시 입력 할 때 리소스를 다시 할당하는 순진한 방법을 보여 줬습니다. 일부 리소스에는 적합하지만 많은 리소스의 경우 적절하지 않을 수 있습니다 (예 : 파일 다시 열기, 동적 컨텍스트를 다시 입력 할 때 파일 시작 부분에 있음). 상당한 오버 헤드.

테일러 캠벨 (예, 관련성 있음)은이 문제를 해결하고 원하는 정확한 의미에 따라 몇 가지 대안을 제시하여 an article in his blag (2009-03-28 항목)을 보유하고 있습니다. 예를 들어, 그는 리소스에 액세스 할 수있는 동적 컨텍스트를 다시 입력 할 수 없게 될 때까지 정리 절차를 호출하지 않을 양식 을 제공합니다.

이렇게 다양한 옵션을 사용할 수 있습니다. Scheme은 매우 다른 언어이며 매우 다른 제약 조건을 가지고 있기 때문에 RAII와 정확히 일치하는 것은 없습니다. 보다 구체적인 사용 사례가 있거나 간단히 언급 한 사용 사례에 대한 자세한 내용이 있으면 좀 더 구체적인 조언을 제공 할 수 있습니다.