10

Common Lispでは、外部リソース(ソケット、ファイルシステムハンドルなど)を管理するための好ましい方法は何ですか?

CommonLispでシンプルなopengl2dプラットフォーマーを作ろうとしています。問題は、OpenGLテクスチャを追跡する方法がよくわからないことです(glDeleteTextures不要になったときに削除する必要があります)。

C ++では、次のスキームを使用することを好みました。

  1. テクスチャクラスを作成する
  2. そのテクスチャクラスのスマート/ウィークポインタを作成します
  3. テクスチャを、ファイル名をテクスチャへの弱いポインタにマップするマップ(辞書/ハッシュテーブル)に格納します。
  4. 新しいテクスチャが要求されたら、マップを調べて、null以外(nil)の弱いポインタが使用可能かどうかを確認します。使用可能な場合は既存のオブジェクトを返し、そうでない場合は新しいテクスチャをロードします。

ただし、このスキームをCommon lispに移植する方法がよくわかりません。理由は、次のとおりです。

  1. デストラクタはありません。
  2. ガベージコレクターがあり、私の実装(WindowsプラットフォームのclozureCL)はファイナライザーをサポートしているようですが、決定論的ではないため、一般的なlispでファイナライザーを使用することはお勧めしません。
  3. を使用してリソースを管理するための好ましい方法は、リソースを(with-*共有したり、関数呼び出しの途中でロード/アンロードしたりできるため、ここでは適切ではないようです。

私が知る限り、利用可能ないくつかのアプローチがあります。

  1. 自動リソース管理をあきらめ、手動で行います。
  2. マクロを使用して、C ++ RAII、weakpointer、smartpointerに似たものを実装します(このコードはおそらく機能しません)。

    (defclass destructible () ())
    
    (defmethod destroy ((obj destructible)) (print (format nil "destroy: ~A" obj)))
    
    (defparameter *destructible-classes-list* nil)
    
    (defmethod initialize-instance :after ((obj destructible) &key)
      (progn
          (push *destructible-classes-list* obj)
          (print (format nil "init-instance: ~A" obj))))
    
    (defmacro with-cleanup (&rest body)
      `(let ((*destructible-classes-list* nil))
        (progn ,@body (mapcar (lambda (x) (destroy x)) *destructible-classes-list*))))
    
    (defclass refdata (destructible)
      ((value :accessor refdata-value :initform nil)
       (ref :accessor refdata-ref :initform 0)
       (weakrefcount :accessor refdata-weakref :initform 0)))
    
    (defmethod incref ((ref refdata))
      (if ref (incf (refdata-ref ref))))
    
    (defmethod decref ((ref refdata))
      (if ref
        (progn (decf (refdata-ref ref))
         (if (<= (refdata-ref ref) 0) 
           (progn (destroy (refdata-value ref))
              (setf (refdata-value ref) nil))))))
    
    (defmethod incweakref ((ref refdata))
      (if ref (incf (refdata-weakref ref))))
    
    (defmethod decweakref ((ref refdata))
      (if ref (decf (refdata-weakref ref))))
    
    (defclass refbase (destructible) ((data :accessor refbase-data :initform nil)))
    
    (defmethod deref ((ref refbase))
      (if (and (refbase-data ref) (refdata-value (refbase-data ref)))
        (refdata-value (refbase-data ref))
        nil))
    
    (defclass strongref (refbase) ())
    
    (defclass weakref (refbase) ())
    
    (defmethod destroy :before ((obj strongref))
      (decref (refbase-data obj)))
    
    (defmethod destroy :before ((obj weakref))
      (decweakref (refbase-data obj)))
    
    (defmethod initialize-instance :after ((obj strongref) &key)
      (incref (refbase-data obj)))
    
    (defmethod initialize-instance :after ((obj weakref) &key)
      (incweakref (refbase-data obj)))
    

それを行うためのより良い方法はありますか?

C ++の概念説明: スマートポインターとは何ですか?いつ使用する必要がありますか?

4

1 に答える 1

9

動的エクステントスコープを処理する場合は、UNWIND-PROTECTを使用します。プログラムがそのスコープを離れると(通常またはエラー時に)、クリーンアップフォームが呼び出されます。そこに割り当てを解除するか、好きなことをしてください。

Lispは、使用済みオブジェクトと未使用オブジェクトを追跡するために、ある種の「リソース」メカニズムを使用することがあります。このようなライブラリは、プールからの高速割り当て、割り当て、初期化、割り当て解除、リソースオブジェクトのマッピングを提供します。CLIMは、プリミティブバージョンを定義します:Resources。CCLには同様のプリミティブバージョンがあります。

「タイマー」を備えたLispでは、割り当てを解除する「オブジェクト」を探す関数を定期的に実行できます。CCLでは、を使用して一定時間スリープするスレッドを使用できますPROCESS-WAIT

コーディングスタイルについて少し:

  • FORMATストリームに直接出力でき、印刷は必要ありません
  • (defmethod foo ((e bar)) (if e ...))IF意味がありません。e常にオブジェクトになります。
  • 多くPROGNは必要ありません。必要に応じて、IFがに置き換えられた ときに削除できますWHEN
于 2012-11-10T20:58:23.033 に答える