I'm wondering about how to use PyDict_SetDefault
without creating a reference count catastrophe.
The documentation doesn't say anything about a stolen reference and some testing shows that it doesn't "steal the reference" of default
. But it increfs it if and only if the key wasn't present in the dictionary.
That seems really complicated to me because it's just too easy to get wrong. I currently use it like this:
item = PyDict_SetDefault(dictionary, key, defaultvalue);
if (item != defaultvalue) {
/* key was present, the item is a borrowed reference and default is at refcount 1.*/
Py_INCREF(item); /* item at refcount 2 */
Py_DECREF(defaultvalue); /* default at refcount 0 */
defaultvalue= NULL;
} else {
/* key wasn't present, item is default and has refcount 2. */
defaultvalue = NULL;
}
At the end the dictionary and I own a reference for item
and default
was cleanly deleted, right?
Is there a better way to deal with the situation without explicitly checking if item == default
that I missed? Is it really that complicated or did I miss the obvious and easy way?
item = PyDict_SetDefault(dictionary, key, defaultvalue);
Py_INCREF(item);
Py_DECREF(defaultvalue);
It doesn't really matter whether item==defaultvalue
- whatever happens you take ownership of item
(by increfing it) and release ownership of defaultvalue
(by decrefing it, assuming you don't want to use it for anything else).
if key
is present in the dictionary then defaultvalue
isn't used, so its refcount stays at 1, and it gets destroyed with decref. item
is returned with a refcount of 1 (because it's stored in the dictionary) and we increment it because we're using it too so item
now has a refcount of 2.
If key
isn't present then defaultvalue
is stored in the dictionary (refcount now 2) used and returned. item
and defaultvalue
are the same. We increment item
(refcount 3) the decref defaultvalue
(refcount 2).
Either way we end in the same place.