ctclreference-counting

Should reference counters always be used when creating a Tcl object?


There's a whole page on the Tcl wiki, but there are a lot of examples and it's hard for me to find them.
Here are two simple cases that I often use:

Tcl_Obj *innerObj = NULL;
innerObj = Tcl_NewListObj(0, NULL);
// And 
Tcl_Obj* dataObj = Tcl_NewStringObj("test", 4);

In these 2 cases, should I use :

  1. Tcl_IncrRefCount(…);
  2. Tcl_DecrRefCount(…);

Solution

  • If you're at all concerned about it, you can do just that. It isn't wrong (and was how the system was originally designed to work in the early alphas of Tcl 8.0). If you are holding the value yourself long-term, you should do so! But it is unnecessary in many common cases.

    Here's one of those cases: you're making the object to set it as the result of the command you are implementing. This is a common case! That operation does not fail (unless you do something utterly loopy) and definitely takes a reference, so you can avoid managing the reference count yourself:

    Tcl_SetObjResult(interp, Tcl_NewIntObj(abc + 123));
    

    If you had to manipulate the reference count, that would be a lot longer, with a temporary variable, etc.

    It's the same if you are appending it to a list you are building; that operation only fails if the "list" isn't a list or if memory allocation fails, and if you control the list and are only putting up to, say, a few million items in the list, the possibility of failure is negligible and you need not handle reference counts yourself.

    That's also true for values you put in a dictionary, and for the keys too if you know they don't already exist (often true when you're building a new one). But if you aren't sure about that, you probably need to manage the reference counts of keys. Tcl 9.0 provides an extra tool for doing that, so you can do this:

    Tcl_Obj *key = Tcl_NewStringObj("the.key", TCL_AUTO_LENGTH);
    Tcl_DictObjPut(NULL, dictObj, key, Tcl_NewIntObj(123)); // assume dictObj is right type
    Tcl_BounceRefCount(key); // delete key if unreferenced
    

    That saves having to increment beforehand and decrement afterwards. (This also applies to working with variables.)

    Some operations require that you hold a reference to the values you pass to them. Most notable among them are the Tcl_Eval family, including Tcl_EvalObjv(); there's too much possibility of internal reference alterations for anything else to be safe.