0
#include <tcl.h>
#include <iostream>
using namespace std;

char* myTraceProc(ClientData clientData, Tcl_Interp* interp, const char* name1, const char* name2, int flags) {
    cout << "myTraceProc" << endl;
    //changing the object
    return NULL;
}

int main(int argc, char* argv[]) {
    Tcl_FindExecutable(argv[0]);
    Tcl_Interp *interp = Tcl_CreateInterp(); 

    Tcl_TraceVar(interp, "database", TCL_TRACE_WRITES, myTraceProc, 0);

    return 0;
}

これは私の c++/tcl プログラムの一部です。実際には問題は示されていませんが、説明しようと思います。

変数databaseにはカスタム タイプがあります。Tcl_RegisterObjType procを使用して登録されます。myTraceProc問題は、 procでトレースされたオブジェクトを変更すると、インタープリターがオブジェクトを複製することです (Tcl_DupInternalRepProcが呼び出されます)。これは、プログラムの望ましい動作ではありません。クローンが作成されず、すべての請求が正確なオブジェクトで行われるとよいでしょう。Tcl_TraceVar のドキュメントを調べましたが、無効にする方法が見つかりませんでした。

4

1 に答える 1

1

まず、Tcl の型システムは、次の点で C++ (および他の多くの言語) で使用されるものとは大きく異なります。

  1. 型は、変数ではなく値に明示的に付加されます。
  2. 値はタイプ間で変更できます。(これは、文字列にシリアル化してからその文字列を解析するか、より効率的なメカニズムを介して行うことができます。詳細は、正確な例に非常に固有です。)

第 2 に、エントリを作成するテーブルを検索する をTcl_RegisterObjType()除いて、他の API と特別な関係はありません。Tcl 自体はどこにも呼び出しません。必要に応じて別の拡張パッケージが型を取得できるようにする以外に、型を登録しても利点はありません。また、どのタイプがあるかについても文書化していません。Tcl の内部型のすべてが登録されているわけではありません — 型のセットは、パッチ バージョン間でさえ保証されていません — また、操作の影響が引数の型に与える影響についての公的な保証はありません (ただし、いくつかは現在、次のようにかなり簡単に推測できます)。リスト操作と辞書操作を使用)。Tcl_GetObjType()T_RegisterObjTypeTcl_GetObjType

これらの点から、使用しているアプローチを変更する必要があります。データベース ハンドルを直接値に入れる代わりに、ハッシュ テーブルで実際のハンドルを検索するために使用できる人間が判読できる文字列を入れます。これは非常に簡単に正しく行うことができ、トリッキーなコーディングはほとんど必要ありません。唯一の欠点は、ハンドルを手動で破棄する必要があることです。通常、これを行うには、closeDatabase $handle操作を行うか、変数に未設定のトレースを設定unset handleして、削除を行うことができます (ローカル変数の場合はプロシージャからのみ)。これは、多くのことについて書かれている古典的なアプローチなので、ここでは詳細には触れません。(このコードも見つかるかもしれませんかなり前に書いた興味深いものです。)

より洗練されたアプローチは、ハンドルを TclOO オブジェクトにバインドすることです。TclOO C API には、TclOO メソッドから簡単に取得できるインスタンス オブジェクトの非表示の内部値としてハンドルを登録できるメカニズムがあります (スクリプト化されているのではなく、TclOO C API を使用している場合)。次に、TclOO で使用されるライフタイム管理コード (適切に定義されたコンストラクターとデストラクタ、包含エンティティが削除されたときのコールバックなど) の恩恵を受けます。これは、多くのTDBC のデータベース ドライバが動作する方法です (たとえば、内部でtdbc::odbc正確に動作します)。

最後に、これが実際のデータベースである場合は、既存のデータベース エクステンションを使用します (TDBC 準拠が推奨されます)。なんで?接続管理を行うために大量のコードを維持する必要がないからです。そのすべてをスクリプト (書きやすい) と他の人が管理する拡張機能に委任できます。C++ からデータベースにアクセスするための呼び出しは、おそらくTcl_EvalObjv最も効率的なパブリック コマンド呼び出し関数を介して、(自己提供の) Tcl コマンドの呼び出しになる可能性があります。

于 2013-11-06T09:18:36.510 に答える