Description edit
The
clt thread, "
Tcl_ObjSetVar2... ,Martin Lembug ,2005-10-12
", and
Bug #1334947
revived the discussion of how to properly manage the reference count of Tcl_Objs.
This is an attempt at clarifying the issue, and a roadmap to improving both the core's refCount management as well as the documentation related to the subject.
1. CategorizationJoe English writes:
There are roughly four classes of Tcl_Obj-related library routines:- Constructors, which return a fresh Tcl_Obj with 0 refcount;
- Readers, which only read the value (but may cause shimmering).
- Consumers, which store a new reference to an existing Tcl_Obj, increment the refcount, and arrange to decrement the refcount at some unspecified point in the future.
- Mutators, which change the Tcl_Obj and can *only* be used with unshared Tcl_Objs (refcount = 0 or 1).
and Donal Fellows adds the category
- Hairy Monsters. Don't give these things refcount==0 objects since they will manipulate the refcount during their processing and might or might not retain a reference.
Please note that the same funtion may belong to different categories with respect to different arguments: for example, as currently implemented (up to Tcl8.5a4), the function
Tcl_ObjSetVar2(interp, part1Ptr, part2Ptr, newValuePtr, flags) is a Reader wrt part1Ptr and part2Ptr, but a Hairy-Monster wrt newValuePtr.
(DKF: It should be noted that there is no guarantee that Tcl_ObjSetVar2 will remain a reader wrt part2ptr; if we ever optimize internal memory management of arrays, that will likely change. This is why knowing which function is what with respect to each argument is hard.)As a general rule, all Tcl commands should be considered to be Hairy-Monsters wrt the objects in the objv array.We hope to improve the documentation wrt to the categorization of the different functions, and also to reduce significantly the population of Hairy-Monsters. As of today, Constructors and Mutators should be properly documented as such.
2. Rules for dealing safely with the different categoriesNote first that
Constructors are not an issue: there is no Tcl_Obj to manage before you call them.
The
always-safe rules are:
- Mutators: pass an unshared object (refCount is 0 or 1). In order to respect copy-on-write semantics, make a copy for your use if you need to modify a shared object, and modify the copy.
- Readers, Consumers and Hairy-Monsters: Tcl_IncrRefCount(objPtr) before calling the library function, Tcl_DecrRefCount(objPtr) on return. This means: assume that every function in the Tcl library that is not a Mutator is a Hairy-Monster.
The
optimal rules in terms of performance and code simplicity (but risky in light of incomplete documentation) are:
- Mutators: pass an unshared object (refCount is 0 or 1). In order to respect copy-on-write semantics, make a copy for your use if you need to modify a shared object, and modify the copy. Use Tcl_IsShared to determine whether you may modify, and Tcl_DuplicateObj to get the copy.
- Readers: if you pass an object with refCount==0, make sure to Tcl_DecrRefCount(objPtr) on return in order not to leak the object.
- Consumers: do not worry about reference counts as the consumer takes care of it, including the freeing of unneeded objects. This is fire-and-forget. Passing a fresh Tcl_Obj* to a consumer means you're through using it.
- Hairy-Monsters: Tcl_IncrRefCount(objPtr) before calling the library function, Tcl_DecrRefCount(objPtr) on return.
See Also edit