Greets, Instantiable Lucy class's will typically have two constructor-type functions: new() and init(). Abstract classes will typically only have init().
(The new/init bifurcation was mentioned briefly in a previous thread: <http://mail-archives.apache.org/mod_mbox/lucene-lucy-dev/200903.mbox/%[email protected]%3e>) When building objects from C, we usually call new(); ANDQuery *and_query = ANDQuery_new(children); All new() does is allocate the blank object and then invoke init(): ANDQuery* ANDQuery_new(VArray *children) { ANDQuery *self = (ANDQuery*)VTable_Make_Obj(ANDQUERY); return ANDQuery_init(self, children); } The limitation of new() is that it does not support subclassing, since the VTable on which we invoke VTable_Make_Obj() is fixed -- in this case, ANDQUERY. However, when invoking a constructor from Host space, we don't have to go through new(). So long as we can find the right VTable, can call VTable_Make_Obj() and init() ourselves. Thus the constructor Perl bindings -- which typically create functions named "new" in Perl space -- do not actually invoke the class's new() function. Instead, they are wrappers around init(). A second subtlety: VTable_Make_Obj has to use calloc rather than malloc, in order to ensure orderly cleanup in the event that an exception occurs midway through object construction. Some classes, e.g. Indexer, IndexReader, will have very elaborate constructors which can fail for any number of reasons. When this happens, the object must be DECREF'd before the exception is thrown, or we leak memory -- which will result in the destructor being invoked. Destructors must clean up individual member variables. However, if the constructor fails before a particular member is assigned, the destructor may mistake a random number at that member's address for a valid object, resulting in a memory error. To guard against this we use calloc to allocate object structs, and ensure that destructors always NULL-check any member they are about to clean up, even if the object could not possibly have functioned properly without that member variable. The DECREF macro is implemented with this in mind. /* If an object is not NULL, decrement its refcount, calling destroy on it * if the refcount drops to 0. */ #define LUCY_DECREF(_self) lucy_Obj_decref((lucy_Obj*)_self) static CHY_INLINE chy_u32_t lucy_Obj_decref(lucy_Obj *self) { if (self != NULL) { return Lucy_Obj_Dec_RefCount(self); } else { return 0; } } DECREF should generally be favored over direct calls to Dec_RefCount() -- which is why it is has a nice, short name. Marvin Humphrey
