Provided by: manpages-zh_1.5.2-1_all bug

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;
       bytes  和   length   成員一起持有一個對象的字符串表示,這是一個已計數的
       (counted)  字符串或二進制串  (binary  string),二進制串可能包含有嵌入的
       null    字節的二進制串。bytes    指向這個字符串表示的第一個字節。length
       成員給出字節數。字節數組的在偏移量                               length
       上,也就是最後一個字節後面必須總是有一個    null;這允許不包含     null
       的字符串表示被作為一個常規的用   null  終結的  C  語言字符串來對待。  C
       程式使用         Tcl_GetStringFromObj         和          Tcl_GetString
       來得到一個對象的字符串表示。如果 bytes 是 NULL,則字符串表示無效。

       一個對象的類型管理它的內部表示。成員 typePtr 指向描述類型的 Tcl_ObjType
       結構。如果 typePtr is 是 NULL,則內部表示無效。

       internalRep
       聯合成員持有一個對象的內部表示。它可以是一個(長)整數,一個雙精度浮點數,或者一個指針、它指向包含這個類型的對象要表示對象所需要的補充信息的值,或者是兩個任意的指針。

       使用                                                           refCount
       成員來通告在什麼時候釋放一個對象的存儲是安全的。它持有到這個對象的活躍引用的計數。維護正確的引用計數是擴展作者的一個關鍵性的責任。在下面的對象的存儲管理
       (STORAGE MANAGEMENT OF OBJECTS) 章節中討論了引用計數。

       儘管擴展的作者可以直接訪問一個                                  Tcl_Obj
       結構的成員,但最好還是使用恰當的過程和宏。例如,擴展作者永遠不要直接讀或修改
       refCount;作為替代,他們應當使用像  Tcl_IncrRefCount   和  Tcl_IsShared
       這樣的宏。

       Tcl
       對象的一個關鍵屬性是它持有兩個表示。典型的,一個對象開始時只包含一個字符串表示:
       它是無類型的並且typePtr    是一個    NULL。分別使用    Tcl_NewObj    或
       Tcl_NewStringObj
       建立包含一個空串的一個對象或一個指定字符串的一個復件。一個對象的字符串值可以使用
       Tcl_GetStringFromObj  或  Tcl_GetString  來獲取並使用  Tcl_SetStringObj
       來改變它。如果如果這個對象以後被傳遞給像              Tcl_GetIntFromObj
       這樣的要求一個特定的內部表示的過程,則這個過程將建立一個內部表示並設置這個對象的
       typePtr。從字符串表示來計算它的內部表示。一個對象的兩個表示是雙重的:
       對一個的改變也將反映到另一個上。例如,Tcl_ListObjReplace
       將修改一個對象的內部表示,下一個到        Tcl_GetStringFromObj       或
       Tcl_GetString 的調用將反映這個改變。

       出於效率的原因以懶惰方式重計算表示。一個過程如       Tcl_ListObjReplace
       對一個表示的改變不立即反映到另一個表示上。作為替代,把另一個表示標記為無效,如果以後需要的話再重新生成。多數
       C                程式員永遠無須關心這是如何完成的,他們只是簡單的使用像
       Tcl_GetBooleanFromObj                或                Tcl_ListObjIndex
       這樣的過程。而實現自己的對象類型的程式員必須檢查無效表示和在需要時標記一個表示為無效。使用過程
       Tcl_InvalidateStringRep
       來標記一個對象的字符串表示為無效並釋放與這個字符串表示相關聯的存儲。

       對象在它的一生當中通常保持一種類型,但是有時一個對象必須從一種類型轉換成另一種類型。例如,一個
       C                  程式可以通過重復調用                 Tcl_AppendToObj
       來在一個對象中建造一個字符串,並接著調用               Tcl_ListObjIndex
       來從一個對象中提取一個列表元素。持有相同字符串的同樣的對象在不同的時候可能有多種不同的內部表示。擴展作者可以使用
       Tcl_ConvertToType
       過程強制把一個對象從一種類型轉換成另一種類型。只有建立新對象類型的程式員才需要關心這是如何作的。作為對象類型實現的一部分,需要定義為一個對象建立一個新的內部表示和改變它
       typePtr  的一個過程。如何建立一個新對象類型請參見   Tcl_RegisterObjType
       手冊頁。

å°å°è±è±¡ç”生å‘命å‘周æœæœŸç¤ç¤ºä¾ä¾‹ EXAMPLE OF THE LIFETIME OF AN OBJECT
       作為一個對象生命周期的一個例子,考慮下列命令序列:
              set x 123
       這裏把一個未知類型的對象賦值給  x,這個對象的  bytes  成員指向  123  而
       length 成員包含 3。對象的 typePtr 成員是 NULL。
              puts "x is $x"
       x 的字符表示是有效的(因為 bytes 是非 NULL)並被這個命令取回。
              incr x
       incr       命令首先通過調用        Tcl_GetIntFromObj        從        x
       (所引用的)的對象的得到一個整數。這個過程檢查這個對象是否已經是一個整數對象。由於它不是,就通過把這個對象的
       internalRep.longValue   成員設置為整數   123,並把這個對象的    typePtr
       設置為指向整數的                                            Tcl_ObjType
       結構,此過程把這個對象轉換成了整數對象。兩個表示現在都是有效的。incr
       增加這個對象的整數內部表示,接著使它的字符串表示無效(通過調用
       Tcl_InvalidateStringRep),原因是這個字符串表示不再與內部表示相對應了。
              puts "x is now $x"
       現在需要 x (所引用的)的對象的字符串表示,要重新計算它。字符串表示現在是
       124。兩個表示又都是有效的了。

å°å°è±è±¡çšçš„å­å­˜å„儲ç®ç®¡çç† 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]));

       另一個例子,incr
       的命令過程在增加變量(所引用的)對象內部表示中的整數之前,必須檢查這個變量(所引用的)對象是否是共享的。如果它是共享的,則需要複製這個對象,目的是避免意外的改變在其他數據結構中值。

ååƒè¦è¦‹ 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.net