Tcl:解释器创建跟踪对象的副本,当它被更改时
Tcl: Interpreter creates copy of traced object whet it goes changed
#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过程注册的。问题是,当我在myTraceProc
过程中对跟踪对象进行更改时,解释器会复制该对象(调用Tcl_DupInternalRepProc
)。这不是程序的预期行为。如果不创建克隆并且所有费用都使用确切的对象完成,那就太好了。我查看了Tcl_TraceVar文档,但没有找到禁用它的方法。
首先,Tcl的类型系统与C++(以及许多其他语言)中使用的类型系统非常不同,因为:
- 类型显式附加到值,而不是变量。
- 值可以在类型之间改变。(这可以通过序列化为字符串然后解析该字符串来完成,也可以通过更有效的机制来完成;详细信息非常特定于确切的示例。
其次,Tcl_RegisterObjType()
与任何其他 API 没有特殊关系,除了 Tcl_GetObjType()
,它在T_RegisterObjType
在其中输入的表中进行查找。Tcl 本身不会在任何地方调用Tcl_GetObjType
;注册类型没有任何好处,只能允许另一个扩展包根据需要获取该类型。我们也不会记录有哪些类型。并非所有 Tcl 的内部类型都被注册了——补丁版本之间甚至不能保证类型集——并且没有公开保证操作对参数类型的影响(尽管有些目前很容易猜到,例如列表和字典操作)。
由于这些要点,您需要更改正在使用的方法。不要直接将数据库句柄放在值中,而是放置一个人类可读的字符串,您可以使用该字符串在哈希表中查找实际句柄。这很容易正确,并且需要的棘手编码要少得多。唯一的缺点是您最终不得不手动处理手柄;通常,您可以通过执行closeDatabase $handle
操作或在变量上设置未设置跟踪来执行此操作,以便您可以只执行unset handle
(或者只是从过程中,如果是局部变量)进行删除。这是一种经典的方法,已经写了很多,所以我不会在这里详细介绍。(您可能还会发现我很久以前编写的这段代码很有趣。
更复杂的方法是将句柄绑定到 TclOO 对象中。TclOO C API 具有一种机制,允许您将句柄注册为实例对象上的隐藏内部值,您可以从 TclOO 方法中轻松检索该值(前提是它们使用 TclOO C API,而不是编写脚本),然后您可以从 TclOO 中使用的生存期管理代码(定义良好的构造函数和析构函数, 删除包含实体时的回调等)。这就是TDBC的数据库驱动程序中有多少工作方式(例如,tdbc::odbc
幕下正是这样做的)。
最后,如果这是您正在与之交谈的真实数据库,请使用现有的数据库扩展(建议符合 TDBC)。为什么?因为这样您就不必维护大量代码来进行连接管理;您可以将所有这些委托给其他人维护的脚本(易于编写)和扩展。然后,您从C++访问数据库的调用可以成为(自我提供的)Tcl命令的调用,可能通过Tcl_EvalObjv
因为这是最高效的公共命令调用函数。
- 用callgrind追踪不必要的副本
- 关于:C++中异常对象的范围:为什么我没有得到副本?
- 在为LINUX创建共享库时,如何避免STL的私有/弱副本
- 检查注册表项是否链接到(或副本)另一个注册表项
- 为什么构建目录中新构建的共享库与安装目录中的副本具有不同的依赖项集?
- C++基于范围的 for 循环和元素副本
- 创建提升::shared_ptr的深层副本
- 如何从构造函数副本 T(const T&)调用对象 T?
- 副本初始化的默认模板参数推导
- C++深浅的副本
- 文件格式的编写解释器(C++ Arduino)
- 将相同共享指针的副本存储在不同的向量中是否是一种好的做法?
- Eigen - matrix.transpose 会创建矩阵的副本吗?
- 将 MatrixXd 的行传递给要修改的函数,而不在 Eigen 中创建副本
- 对如何制作双链表的深度副本感到困惑?
- 从嵌入式解释器捕获 python 窗口输出C++
- 为什么 std::string s = "123" 当不涉及副本时被视为复制初始化?
- 指向基类的指针的 std::vector 的深层副本
- 解释器在跟踪中创建对象的副本
- Tcl:解释器创建跟踪对象的副本,当它被更改时