The "trick" is to use Automation compatible types, e.g. BSTR instead of ASCIIZ, safe arrays instead of other kind of arrays, object variables instead of pointers to custom allocated memory, etc. VariantClear knows how to manage them.
For a VT_BSTR variant, you allocate an string with SysAllocString and store the returned pointer in the structure. VariantClear will call SysFreeString to free the memory used by the string.
For a safe array, you allocate the memory and manage the elements using the API safe arrays functions. VariantClear will call SafeAerrayDestroy, that knows how to free the memory used by the array since a safe array includes information about the kind of data stored and the number of elements.
For an object variable, VariantClear will call the Release method of the object.
Now, if you want to use other kind of strings or arrays, then you will have to free the memory yourself, because VariantClear has no means to know how to do it.
For a perfect solution, just include another of my suggestions: native support for safe arrays.