other languages
other sections
Tcl_Obj(3tcl) | Tcl Library Procedures | Tcl_Obj(3tcl) |
NAME¶
Tcl_NewObj, Tcl_DuplicateObj, Tcl_IncrRefCount, Tcl_DecrRefCount, Tcl_IsShared, Tcl_InvalidateStringRep - 操纵 Tcl 对象总览 SYNOPSIS¶
#include <tcl.h>Tcl_Obj * Tcl_NewObj()Tcl_Obj * Tcl_DuplicateObj(objPtr)Tcl_IncrRefCount(objPtr)Tcl_DecrRefCount(objPtr)int Tcl_IsShared(objPtr)Tcl_InvalidateStringRep(objPtr)
参数 ARGUMENTS¶
- Tcl_Obj *objPtr (in)
- 指向一个对象;必须是以前调用
Tcl_NewObj 返回的结果。
介绍 INTRODUCTION¶
这个手册页提供了对 Tcl 对象以及如何使用它们的一个概述。它还描述了管理 Tcl 对象的一些一般过程。使用这些过程来建立和复制对象,和增加和减少到对象的引用(指针)计数。这些过程与那些在特定类型的对象如 Tcl_GetIntFromObj 和 Tcl_ListObjAppendElement 上进行操作的过程联合使用。单独的过程和它们所操纵的数据结构被放在一起描述。 Tcl 的双端口( dual-ported)对象为存储和交换 Tcl 值提供了一个通用的机制。它们在很大程度上替代了 Tcl 中字符串的使用。例如,它们被用来存储变量值、命令参数、命令结果、和脚本。Tcl 对象外在表现很象字符串,但它还持有可以被更加有效的操纵的内部表示。例如,现在一个 Tcl 列表被表示为持有列表的字符串表示的一个对象,如同到每个列表元素的指针的一个数组。双端口对象避免了运行时的类型转换。它们还提高了许多操作的速度,原因是可以立即获得一个适当的表示。编译器自身使用 Tcl 对象来缓存(cache)作为编译脚本的结果的字节码指令。 这两种表示互为缓存并且被以懒惰方式计算。就是说,每个表示都只在需要时才被计算,它被从另一种表示计算出来,而一旦被计算出来了,它就被保存起来。除此之外,其中一个表示的改变将使另一个表示成为无效 。举个例子,一个做整数运算的 Tcl 程序可以在一个变量的内部机器整数表示上进行直接操作,而不需要经常性的在整数和字符串之间进行转换。只有在需要这个变量的值的一个字符串表示的时候,比如打印它,程序才重新生成这个整数的字符串表示。尽管对象包含一个内部表示,但它们的语义仍是依据字符串定义的: 总是可以获取最新的字符串,在取回对象的字符串表示的时候,对对象的任何改变都将反映到取回的那个字符串上。因为这个表示是无效的并被重新生成了,扩展作者直接访问 Tcl_Obj 的字段是很危险的。最好使用 Tcl_GetStringFromObj 和 Tcl_GetString 这样的过程来访问 Tcl_Obj 信息。 在堆上分配对象,使用到它们的 Tcl_Obj 结构的指针引用对象。对象要尽可能的共享。这将显著的缩减存储需求,原因是一些对象比如长列表是非常大的。还有,多数 Tcl 值只是被读而从不被修改。尤其是过程参数,它们可以在调用和被调用的过程之间共享。赋值和参数绑定是通过简单的赋予到这个值的一个指针完成的。使用引用计数来确定什么时候归还一个对象的存储是安全的。 Tcl 对象是有类型的(typed)。一个对象的内部表示由它自己的类型来控制。在 Tcl 核心中预定义了七种类型,其中包括:整数、双精度浮点数、列表、和字节码。扩展作者可是使用 Tcl_RegisterObjType 过程来扩展类型的集合。对象结构 THE TCL_OBJ STRUCTURE¶
每个 Tcl 对象都被表示为一个 Tcl_Obj 结构,其定义如下。typedef struct Tcl_Obj { int refCount; char * bytes; int length; Tcl_ObjType * typePtr; union { long longValue; double doubleValue; VOID * otherValuePtr; struct { VOID * ptr1; VOID * ptr2; } twoPtrValue; } internalRep; } Tcl_Obj;
对象生命周期示例 EXAMPLE OF THE LIFETIME OF AN OBJECT¶
作为一个对象生命周期的一个例子,考虑下列命令序列:set x 123
puts "x is $x"
incr x
puts "x is now $x"
对象的存储管理 STORAGE MANAGEMENT OF OBJECTS¶
Tcl 对象在堆上分配,并且要尽可能的共享对象来缩减存储需求。使用引用计数来确定何时一个对象不再被需要并可以被安全的释放。刚用 Tcl_NewObj 或 Tcl_NewStringObj 建立的对象的 refCount 是 0。当建立到这个对象的一个新引用时,使用宏 Tcl_IncrRefCount 增加引用计数。当不再需要一个引用的时候 ,使用 Tcl_DecrRefCount 减少引用计数,而且如果这个对象的引用计数下降到零,就释放它的存储。被不同的代码或数据结构共享的一个对象的 refCount 大于 1。增加一个对象的引用计数来确保它不会被过早释放或者它的值被意外的改变。 举个例子,字节码解释器在调用者和被调用的过程之间共享参数对象,以避免复制对象。它把调用者的实际参数的对象赋值给过程的形式参数变量。此时,它调用 Tcl_IncrRefCount 来增加每个实际参数(所引用的)的对象的引用计数,原因是有了从形式参数到这个对象的一个新引用。在被调用的过程返回的时候,解释器调用 Tcl_DecrRefCount 来减少每个参数的引用计数。当一个对象的引用下降到小于等于零的时候, Tcl_DecrRefCount 归还它的存储。多数命令过程不是必须关心引用计数的,原因是它们立即使用一个对象的值并且在它们返回之后不保留到这个对象的指针。但是,如果它们把到一个对象的指针保留到一个数据结构中,则他们必须注意要增加它的引用计数,原因是这个保留的指针是一个新引用。 象 lappend 和 linsert 这样的直接修改对象的命令过程必须注意要在修改一个共享的对象之前复制它。 他们必须首先调用 Tcl_IsShared 来检查这个对象是否是共享的。如果对象是共享的,则他们必须使用 Tcl_DuplicateObj 复制这个对象;它返回原始对象的一个新复制品,其 refCount 是 0。如果对象未被共享,则命令过程“拥有”这个对象并可以安全的直接修改它。例如,下列代码出现在实现 linsert 的命令过程当中。通过在 index 的前面插入 objc-3 新元素,这个过程修改在 objv[1] 中传递给它的列表对象 。listPtr = objv[1]; if (Tcl_IsShared(listPtr)) { listPtr = Tcl_DuplicateObj(listPtr); } result = Tcl_ListObjReplace(interp, listPtr, index, 0, (objc-3), &(objv[3]));
参见 SEE ALSO¶
Tcl_ConvertToType, Tcl_GetIntFromObj, Tcl_ListObjAppendElement, Tcl_ListObjIndex, Tcl_ListObjReplace, Tcl_RegisterObjType关键字 KEYWORDS¶
internal representation, object, object creation, object type, reference counting, string representation, type conversion[中文版维护人]¶
寒蝉退士[中文版最新更新]¶
2001/10/30《中国 Linux 论坛 man 手册页翻译计划》:¶
http://cmpp.linuxforum.net8.0 | Tcl |